Skip to content

Commit

Permalink
backport UI: show token expiring warning (#23762)
Browse files Browse the repository at this point in the history
Co-authored-by: Chelsea Shaw <[email protected]>
  • Loading branch information
1 parent cd1d91d commit 3e8b670
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 24 deletions.
3 changes: 3 additions & 0 deletions changelog/23143.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: Surface warning banner if UI has stopped auto-refreshing token
```
55 changes: 55 additions & 0 deletions ui/app/components/token-expire-warning.hbs
Original file line number Diff line number Diff line change
@@ -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}}
27 changes: 27 additions & 0 deletions ui/app/components/token-expire-warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
21 changes: 0 additions & 21 deletions ui/app/templates/components/token-expire-warning.hbs

This file was deleted.

2 changes: 1 addition & 1 deletion ui/app/templates/vault/cluster.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
41 changes: 39 additions & 2 deletions ui/tests/integration/components/token-expire-warning-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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');
});
});

0 comments on commit 3e8b670

Please sign in to comment.