Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Show token expiring warning #23143

Merged
merged 19 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -40,7 +40,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');
});
});
Loading