mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 02:02:43 +00:00
backport UI: show token expiring warning (#23762)
Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
cd1d91dbf3
commit
3e8b670f18
3
changelog/23143.txt
Normal file
3
changelog/23143.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: Surface warning banner if UI has stopped auto-refreshing token
|
||||
```
|
||||
55
ui/app/components/token-expire-warning.hbs
Normal file
55
ui/app/components/token-expire-warning.hbs
Normal file
@@ -0,0 +1,55 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
{{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}}
|
||||
<Hds::Alert @type="page" @color="critical" data-test-token-expired-banner as |A|>
|
||||
<A.Title>Error</A.Title>
|
||||
<A.Description>
|
||||
Your auth token expired on
|
||||
{{date-format @expirationDate "MMMM do yyyy, h:mm:ss a"}}. You will need to re-authenticate.
|
||||
</A.Description>
|
||||
<A.Link::Standalone @icon="arrow-right" @iconPosition="trailing" @text="Reauthenticate" @route="vault.cluster.logout" />
|
||||
</Hds::Alert>
|
||||
{{else}}
|
||||
<section class="section">
|
||||
<div class="container is-widescreen">
|
||||
{{#if (and this.showWarning @allowingExpiration this.canDismiss)}}
|
||||
<Hds::Alert
|
||||
@type="inline"
|
||||
@color="warning"
|
||||
@onDismiss={{fn (mut this.canDismiss) false}}
|
||||
class="has-top-margin-s"
|
||||
data-test-token-expiring-banner
|
||||
as |A|
|
||||
>
|
||||
<A.Title>Session will expire</A.Title>
|
||||
<A.Description>
|
||||
We've stopped auto-renewing your token due to inactivity. It will expire in
|
||||
{{date-from-now @expirationDate}}
|
||||
on
|
||||
{{date-format @expirationDate "MMMM do yyyy, h:mm:ss a O"}}.
|
||||
</A.Description>
|
||||
<A.Button
|
||||
@text="Renew token"
|
||||
@color="secondary"
|
||||
@icon={{if this.renewToken.isRunning "loading" "reload"}}
|
||||
@iconPosition="trailing"
|
||||
disabled={{this.renewToken.isRunning}}
|
||||
{{on "click" (perform this.renewToken)}}
|
||||
data-test-renew-token-button
|
||||
/>
|
||||
<A.Link::Standalone
|
||||
@icon="arrow-right"
|
||||
@iconPosition="trailing"
|
||||
@color="secondary"
|
||||
@text="Log out"
|
||||
@route="vault.cluster.logout"
|
||||
/>
|
||||
</Hds::Alert>
|
||||
{{/if}}
|
||||
{{yield}}
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
@@ -5,9 +5,36 @@
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { later } from '@ember/runloop';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
export default class TokenExpireWarning extends Component {
|
||||
@service auth;
|
||||
@service router;
|
||||
@tracked canDismiss = true;
|
||||
|
||||
handleRenew() {
|
||||
return new Promise((resolve) => {
|
||||
later(() => {
|
||||
this.auth
|
||||
.renew()
|
||||
.then(() => {
|
||||
// This renewal was triggered by an explicit user action,
|
||||
// so this will reset the time inactive calculation
|
||||
this.auth.setLastFetch(Date.now());
|
||||
})
|
||||
.finally(() => {
|
||||
resolve();
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
@task
|
||||
*renewToken() {
|
||||
yield this.handleRenew();
|
||||
}
|
||||
|
||||
get showWarning() {
|
||||
const currentRoute = this.router.currentRouteName;
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
{{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}}
|
||||
<Hds::Alert @type="page" @color="critical" as |A|>
|
||||
<A.Title>Error</A.Title>
|
||||
<A.Description>
|
||||
Your auth token expired on
|
||||
{{date-format @expirationDate "MMMM do yyyy, h:mm:ss a"}}. You will need to re-authenticate.
|
||||
</A.Description>
|
||||
<A.Link::Standalone @icon="arrow-right" @iconPosition="trailing" @text="Reauthenticate" @route="vault.cluster.logout" />
|
||||
</Hds::Alert>
|
||||
{{else}}
|
||||
<section class="section">
|
||||
<div class="container is-widescreen">
|
||||
{{yield}}
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
|
||||
{{#if this.auth.isActiveSession}}
|
||||
<TokenExpireWarning @expirationDate={{this.auth.tokenExpirationDate}}>
|
||||
<TokenExpireWarning @expirationDate={{this.auth.tokenExpirationDate}} @allowingExpiration={{this.auth.allowExpiration}}>
|
||||
{{outlet}}
|
||||
</TokenExpireWarning>
|
||||
{{else}}
|
||||
|
||||
@@ -18,7 +18,7 @@ module('Integration | Component | token-expire-warning', function (hooks) {
|
||||
|
||||
await render(hbs`<TokenExpireWarning @expirationDate={{this.expirationDate}}/>`);
|
||||
await waitUntil(() => find('#modal-overlays'));
|
||||
assert.dom().includesText('Your auth token expired on');
|
||||
assert.dom('[data-test-token-expired-banner]').includesText('Your auth token expired on');
|
||||
});
|
||||
|
||||
test('it does not render a warning when the token is not expired', async function (assert) {
|
||||
@@ -30,8 +30,45 @@ module('Integration | Component | token-expire-warning', function (hooks) {
|
||||
<p>Do not worry, your token has not expired.</p>
|
||||
</TokenExpireWarning>
|
||||
`);
|
||||
await waitUntil(() => find('#modal-overlays'));
|
||||
assert.dom().doesNotIncludeText('Your auth token expired on');
|
||||
assert.dom().includesText('Do not worry');
|
||||
});
|
||||
|
||||
test('it renders a warning when the token is no longer renewing', async function (assert) {
|
||||
const expirationDate = addMinutes(Date.now(), 3);
|
||||
this.set('expirationDate', expirationDate);
|
||||
this.set('allowingExpiration', false);
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
<TokenExpireWarning @expirationDate={{this.expirationDate}} @allowingExpiration={{this.allowingExpiration}}>
|
||||
<p data-test-content>This is the content</p>
|
||||
</TokenExpireWarning>
|
||||
`
|
||||
);
|
||||
assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner');
|
||||
assert.dom('[data-test-token-expiring-banner]').doesNotExist('Does not show token expiring banner');
|
||||
assert.dom('[data-test-content]').hasText('This is the content');
|
||||
|
||||
await this.set('allowingExpiration', true);
|
||||
assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner');
|
||||
assert.dom('[data-test-token-expiring-banner]').exists('Shows token expiring banner');
|
||||
assert.dom('[data-test-content]').hasText('This is the content');
|
||||
});
|
||||
|
||||
test('Does not render a warning if no expiration date', async function (assert) {
|
||||
this.set('expirationDate', null);
|
||||
this.set('allowingExpiration', true);
|
||||
|
||||
await render(
|
||||
hbs`
|
||||
<TokenExpireWarning @expirationDate={{this.expirationDate}} @allowingExpiration={{this.allowingExpiration}}>
|
||||
<p data-test-content>This is the content</p>
|
||||
</TokenExpireWarning>
|
||||
`
|
||||
);
|
||||
assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner');
|
||||
assert.dom('[data-test-token-expiring-banner]').doesNotExist('Does not show token expiring banner');
|
||||
assert.dom('[data-test-content]').hasText('This is the content');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user