From 84ab85a30681917400ab3b9819265b823f49b992 Mon Sep 17 00:00:00 2001 From: Matthieu Huin Date: Wed, 17 Nov 2021 22:46:53 +0100 Subject: [PATCH] web UI: Add a credentials renew modal Check every second for an authenticated user's token expiration. If the token has expired, display a modal providing a link to log in again. Closing the modal properly logs the user out. Change-Id: I0baa4f415bdc61735fc42f9fd80a58309976096f --- web/src/ZuulAuthProvider.jsx | 8 ---- web/src/containers/auth/Auth.jsx | 70 +++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/web/src/ZuulAuthProvider.jsx b/web/src/ZuulAuthProvider.jsx index 94deff9617..7f844e843e 100644 --- a/web/src/ZuulAuthProvider.jsx +++ b/web/src/ZuulAuthProvider.jsx @@ -143,14 +143,6 @@ class ZuulAuthProvider extends React.Component { } }) - // This is called when a token is expired - userManager.events.addAccessTokenExpired(() => { - console.log('Auth token expired') - userManager.removeUser() - this.props.dispatch(userLoggedOut()) - this.props.channel.postMessage({ 'type': 'signOut' }) - }) - // This is called about 1 minute before a token is expired. We will try // to renew the token. We use a leader election so that only one tab // makes the attempt; the others will receive the token via a broadcast diff --git a/web/src/containers/auth/Auth.jsx b/web/src/containers/auth/Auth.jsx index 02b2a69914..31d86e8445 100644 --- a/web/src/containers/auth/Auth.jsx +++ b/web/src/containers/auth/Auth.jsx @@ -52,6 +52,7 @@ class AuthContainer extends React.Component { info: PropTypes.object, auth: PropTypes.object, // Props coming from withAuth + userManager: PropTypes.object, signIn: PropTypes.func, signOut: PropTypes.func, } @@ -61,17 +62,55 @@ class AuthContainer extends React.Component { this.state = { isModalOpen: false, showZuulClientConfig: false, + isSessionExpiredModalOpen: false, } this.handleModalToggle = () => { this.setState(({ isModalOpen }) => ({ isModalOpen: !isModalOpen })) } + this.handleSessionExpiredModalToggle = () => { + this.setState(({ isSessionExpiredModalOpen }) => ({ + isSessionExpiredModalOpen: !isSessionExpiredModalOpen + })) + } this.handleConfigToggle = () => { this.setState(({ showZuulClientConfig }) => ({ showZuulClientConfig: !showZuulClientConfig })) } + this.onAccessTokenExpired = () => { + // If the token has expired, show the modal + console.debug('Token expired') + this.setState(() => ({ + isSessionExpiredModalOpen: true, + isModalOpen: false, + })) + } + this.onUserLoaded = () => { + // If another tab logged in while our expired modal is shown, go + // ahead and clear it. + console.debug('User signed in') + this.setState(() => ({ + isSessionExpiredModalOpen: false, + })) + } + } + + clickOnSignIn() { + const redirect_target = window.location.href.slice(getHomepageUrl().length) + localStorage.setItem('zuul_auth_redirect', redirect_target) + this.props.signIn() + } + + componentDidMount() { + this.props.userManager.events.addAccessTokenExpired(this.onAccessTokenExpired) + this.props.userManager.events.addUserLoaded(this.onUserLoaded) + } + + componentWillUnmount() { + this.props.userManager.events.removeAccessTokenExpired(this.onAccessTokenExpired) + this.props.userManager.events.removeUserLoaded(this.onUserLoaded) } componentDidUpdate() { @@ -96,6 +135,30 @@ class AuthContainer extends React.Component { return ZCconfig } + renderCredentialsExpiredModal() { + const { isSessionExpiredModalOpen } = this.state + return + { + this.handleSessionExpiredModalToggle() + this.props.signOut() + }}> + Your session has expired.   + + + + } + renderModal() { const { user, tenant, timezone } = this.props const { isModalOpen, showZuulClientConfig } = this.state @@ -164,11 +227,7 @@ class AuthContainer extends React.Component { @@ -185,6 +244,7 @@ class AuthContainer extends React.Component {  {user.data.profile.preferred_username}  + {this.renderCredentialsExpiredModal()} ) }