summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Fertser <fercerpav@gmail.com>2024-07-05 13:46:38 +0300
committerSurya Venkatesan <suryav@ami.com>2024-08-29 16:56:26 +0300
commit83d70f7e8c83d7f082f2774a793cbee75fb414a0 (patch)
treed96637d3d47b2e989bbeb06f284c4c37e0091115
parent421273fc9c7136c7f9794bcd7152b6419358ea3d (diff)
downloadwebui-vue-83d70f7e8c83d7f082f2774a793cbee75fb414a0.tar.xz
Handle expired passwords Redfish standard way
A password can expire at any moment during session lifetime and bmcweb starts returning 403 Forbidden errors to the requests made after that. The response contains clear indication of the condition in the standard `@Message.ExtendedInfo` attribute which is an array of Message objects. Previously the code was trying to detect this condition by querying AccountService after logging in but this approach doesn't work when password expires mid-session. Also it was limited to BMC-managed accounts and used hardcoded account URIs in violation of Redfish spec. This patch adds to the interceptor of 403 error so that the user is automatically redirected to the password change page as soon as the condition is detected. The same message is also present in the session creation POST response 201 if the password expired before the log in attempt, in this case the session is created as usual but the user is automatically redirected to password change page before any further requests are made. Tested: logging in, navigating, logging out with non-expired password. Logging in, navigating, then running `passwd -e <accountname>` via ssh leads to functional password change page on the next request and then navigating proceeds normally, and logging out too. If password is expired before logging in the user gets redirected to the password change page automatically after logging in. Fixes: https://github.com/openbmc/webui-vue/issues/118 Change-Id: I03f5ee2526a4bb1d35d3bbea1142fea077d6bfed Signed-off-by: Paul Fertser <fercerpav@gmail.com> Signed-off-by: Surya Venkatesan <suryav@ami.com>
-rw-r--r--src/store/api.js22
-rw-r--r--src/store/modules/Authentication/AuthenticanStore.js3
-rw-r--r--src/views/Login/Login.vue10
3 files changed, 24 insertions, 11 deletions
diff --git a/src/store/api.js b/src/store/api.js
index 45ffc3c9..7d727562 100644
--- a/src/store/api.js
+++ b/src/store/api.js
@@ -1,4 +1,5 @@
import Axios from 'axios';
+import router from '../router';
import { setupCache, buildWebStorage } from 'axios-cache-interceptor';
//Do not change store import.
@@ -36,11 +37,14 @@ api.interceptors.response.use(undefined, (error) => {
}
}
+ // Check if action is unauthorized.
if (response.status == 403) {
- // Check if action is unauthorized.
- // Toast error message will appear on screen
- // when the action is unauthorized.
- store.commit('global/setUnauthorized');
+ if (isPasswordExpired(response)) {
+ router.push('/change-password');
+ } else {
+ // Toast error message will appear on screen.
+ store.commit('global/setUnauthorized');
+ }
}
return Promise.reject(error);
@@ -84,3 +88,13 @@ export const getResponseCount = (responses) => {
errorCount,
};
};
+
+export const isPasswordExpired = (response) => {
+ let extInfoMsgs = response?.data?.['@Message.ExtendedInfo'];
+ return (
+ extInfoMsgs &&
+ extInfoMsgs.find(
+ (i) => i.MessageId.split('.')[4] === 'PasswordChangeRequired',
+ )
+ );
+};
diff --git a/src/store/modules/Authentication/AuthenticanStore.js b/src/store/modules/Authentication/AuthenticanStore.js
index 3ad41c6b..b64def06 100644
--- a/src/store/modules/Authentication/AuthenticanStore.js
+++ b/src/store/modules/Authentication/AuthenticanStore.js
@@ -1,4 +1,4 @@
-import api from '@/store/api';
+import api, { isPasswordExpired } from '@/store/api';
import Cookies from 'js-cookie';
import router from '@/router';
import { roles } from '@/router/routes';
@@ -59,6 +59,7 @@ const AuthenticationStore = {
commit('authSuccess', {
session: response.headers['location'],
});
+ return isPasswordExpired(response);
})
.catch((error) => {
commit('authError');
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index 213dd481..0878d0ea 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -69,6 +69,7 @@ import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
import { useVuelidate } from '@vuelidate/core';
import { ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
+import i18n from '@/i18n';
import Alert from '@/components/Global/Alert';
import InputPasswordToggle from '@/components/Global/InputPasswordToggle';
@@ -132,14 +133,11 @@ export default {
const password = this.userInfo.password;
this.$store
.dispatch('authentication/login', { username, password })
- .then(() => {
- localStorage.setItem('storedLanguage', this.userLocale);
+ .then((PasswordChangeRequired) => {
+ localStorage.setItem('storedLanguage', i18n.locale);
localStorage.setItem('storedUsername', username);
this.$store.commit('global/setUsername', username);
- this.$store.commit('global/setLanguagePreference', this.userLocale);
- return this.$store.dispatch('authentication/getUserInfo', username);
- })
- .then(({ PasswordChangeRequired }) => {
+ this.$store.commit('global/setLanguagePreference', i18n.locale);
if (PasswordChangeRequired) {
this.$router.push('/change-password');
} else {