summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDamian Celico <damianx.celico@intel.com>2022-11-24 04:00:53 +0300
committerKiran Kumar Ballapalli <kirankumarb@ami.com>2023-03-27 19:39:34 +0300
commitaeb19816e67f6d3ffb1b37c95d813a25b8be1d7b (patch)
tree0b760854f8adc45a3e909a3b1ccd88655a139705 /src
parent568b8a93af49d35891f042f73add850cfa651308 (diff)
downloadwebui-vue-aeb19816e67f6d3ffb1b37c95d813a25b8be1d7b.tar.xz
Added route restrictions based on user privilege
This commit allows us to add 'exclusiveToRoles' field to route config files, with the list of roles that can access this resource, if needed. In this case, only Administrator can access Virtual-Media page and SOL console, and it is blocked for other users. Signed-off-by: Sivaprabu Ganesan <sivaprabug@ami.com> Change-Id: Ibcee18bd92d97c34414ecaf2caf6af28070c5538
Diffstat (limited to 'src')
-rw-r--r--src/components/AppHeader/AppHeader.vue3
-rw-r--r--src/components/AppNavigation/AppNavigation.vue15
-rw-r--r--src/components/AppNavigation/AppNavigationMixin.js8
-rw-r--r--src/env/components/AppNavigation/intel.js9
-rw-r--r--src/env/router/intel.js9
-rw-r--r--src/router/index.js32
-rw-r--r--src/router/routes.js9
-rw-r--r--src/store/modules/Authentication/AuthenticanStore.js6
-rw-r--r--src/store/modules/GlobalStore.js5
-rw-r--r--src/views/Login/Login.vue12
10 files changed, 96 insertions, 12 deletions
diff --git a/src/components/AppHeader/AppHeader.vue b/src/components/AppHeader/AppHeader.vue
index 84e4588f..a1984953 100644
--- a/src/components/AppHeader/AppHeader.vue
+++ b/src/components/AppHeader/AppHeader.vue
@@ -155,6 +155,9 @@ export default {
isAuthorized() {
return this.$store.getters['global/isAuthorized'];
},
+ userPrivilege() {
+ return this.$store.getters['global/userPrivilege'];
+ },
serverStatus() {
return this.$store.getters['global/serverStatus'];
},
diff --git a/src/components/AppNavigation/AppNavigation.vue b/src/components/AppNavigation/AppNavigation.vue
index acfabe76..a5f81051 100644
--- a/src/components/AppNavigation/AppNavigation.vue
+++ b/src/components/AppNavigation/AppNavigation.vue
@@ -29,7 +29,7 @@
<b-collapse :id="navItem.id" tag="ul" class="nav-item__nav">
<li class="nav-item">
<router-link
- v-for="(subNavItem, i) of navItem.children"
+ v-for="(subNavItem, i) of filteredNavItem(navItem.children)"
:key="i"
:to="subNavItem.route"
:data-test-id="`nav-item-${subNavItem.id}`"
@@ -67,6 +67,7 @@ export default {
data() {
return {
isNavigationOpen: false,
+ currentUserRole: null,
};
},
watch: {
@@ -78,12 +79,24 @@ export default {
},
},
mounted() {
+ this.getPrivilege();
this.$root.$on('toggle-navigation', () => this.toggleIsOpen());
},
methods: {
toggleIsOpen() {
this.isNavigationOpen = !this.isNavigationOpen;
},
+ getPrivilege() {
+ this.currentUserRole = this.$store?.getters['global/userPrivilege'];
+ },
+ filteredNavItem(navItem) {
+ if (this.currentUserRole) {
+ return navItem.filter(({ exclusiveToRoles }) => {
+ if (!exclusiveToRoles?.length) return true;
+ return exclusiveToRoles.includes(this.currentUserRole);
+ });
+ } else return navItem;
+ },
},
};
</script>
diff --git a/src/components/AppNavigation/AppNavigationMixin.js b/src/components/AppNavigation/AppNavigationMixin.js
index bbbbb1ee..61230988 100644
--- a/src/components/AppNavigation/AppNavigationMixin.js
+++ b/src/components/AppNavigation/AppNavigationMixin.js
@@ -6,6 +6,12 @@ import IconSettings from '@carbon/icons-vue/es/settings/16';
import IconSecurity from '@carbon/icons-vue/es/security/16';
import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16';
import IconDataBase from '@carbon/icons-vue/es/data--base--alt/16';
+const roles = {
+ administrator: 'Administrator',
+ operator: 'Operator',
+ readonly: 'ReadOnly',
+ noaccess: 'NoAccess',
+};
const AppNavigationMixin = {
components: {
@@ -95,6 +101,7 @@ const AppNavigationMixin = {
id: 'serial-over-lan',
label: this.$t('appNavigation.serialOverLan'),
route: '/operations/serial-over-lan',
+ exclusiveToRoles: [roles.administrator],
},
{
id: 'server-power-operations',
@@ -105,6 +112,7 @@ const AppNavigationMixin = {
id: 'virtual-media',
label: this.$t('appNavigation.virtualMedia'),
route: '/operations/virtual-media',
+ exclusiveToRoles: [roles.administrator],
},
],
},
diff --git a/src/env/components/AppNavigation/intel.js b/src/env/components/AppNavigation/intel.js
index 3fe0ad1c..0688a05e 100644
--- a/src/env/components/AppNavigation/intel.js
+++ b/src/env/components/AppNavigation/intel.js
@@ -7,6 +7,13 @@ import IconSecurity from '@carbon/icons-vue/es/security/16';
import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16';
import IconDataBase from '@carbon/icons-vue/es/data--base--alt/16';
+const roles = {
+ administrator: 'Administrator',
+ operator: 'Operator',
+ readonly: 'ReadOnly',
+ noaccess: 'NoAccess',
+};
+
const AppNavigationMixin = {
components: {
iconOverview: IconDashboard,
@@ -85,6 +92,7 @@ const AppNavigationMixin = {
id: 'serial-over-lan',
label: this.$t('appNavigation.serialOverLan'),
route: '/operations/serial-over-lan',
+ exclusiveToRoles: [roles.administrator],
},
{
id: 'server-power-operations',
@@ -95,6 +103,7 @@ const AppNavigationMixin = {
id: 'virtual-media',
label: this.$t('appNavigation.virtualMedia'),
route: '/operations/virtual-media',
+ exclusiveToRoles: [roles.administrator],
},
],
},
diff --git a/src/env/router/intel.js b/src/env/router/intel.js
index fd8ed77c..5f3ee6eb 100644
--- a/src/env/router/intel.js
+++ b/src/env/router/intel.js
@@ -27,6 +27,13 @@ import VirtualMedia from '@/views/Operations/VirtualMedia';
import Power from '@/views/ResourceManagement/Power';
import i18n from '@/i18n';
+const roles = {
+ administrator: 'Administrator',
+ operator: 'Operator',
+ readonly: 'ReadOnly',
+ noaccess: 'NoAccess',
+};
+
const routes = [
{
path: '/login',
@@ -217,6 +224,7 @@ const routes = [
component: SerialOverLan,
meta: {
title: i18n.t('appPageTitle.serialOverLan'),
+ exclusiveToRoles: [roles.administrator],
},
},
{
@@ -233,6 +241,7 @@ const routes = [
component: VirtualMedia,
meta: {
title: i18n.t('appPageTitle.virtualMedia'),
+ exclusiveToRoles: [roles.administrator],
},
},
{
diff --git a/src/router/index.js b/src/router/index.js
index 3cd52264..bcb2c7a2 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -8,16 +8,25 @@ import store from '../store';
import routes from './routes';
Vue.use(VueRouter);
-
const router = new VueRouter({
base: process.env.BASE_URL,
routes,
linkExactActiveClass: 'nav-link--current',
});
-router.beforeEach((to, from, next) => {
+function allowRouterToNavigate(to, next, currentUserRole) {
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (store.getters['authentication/isLoggedIn']) {
+ if (to.meta.exclusiveToRoles) {
+ // The privilege for the specific router was verified using the
+ // exclusiveToRoles roles in the router.
+ if (to.meta.exclusiveToRoles.includes(currentUserRole)) {
+ next();
+ } else {
+ next('*');
+ }
+ return;
+ }
next();
return;
}
@@ -25,6 +34,25 @@ router.beforeEach((to, from, next) => {
} else {
next();
}
+}
+
+router.beforeEach((to, from, next) => {
+ let currentUserRole = store.getters['global/userPrivilege'];
+ // condition will get satisfied if user refreshed after login
+ if (!currentUserRole && store.getters['authentication/isLoggedIn']) {
+ // invoke API call to get the role ID
+ let username = localStorage.getItem('storedUsername');
+ store.dispatch('authentication/getUserInfo', username).then((response) => {
+ if (response?.RoleId) {
+ // set role ID
+ store.commit('global/setPrivilege', response.RoleId);
+ // allow the route to continue
+ allowRouterToNavigate(to, next, response.RoleId);
+ }
+ });
+ } else {
+ allowRouterToNavigate(to, next, currentUserRole);
+ }
});
export default router;
diff --git a/src/router/routes.js b/src/router/routes.js
index 3cbdabce..1404da5e 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -31,6 +31,13 @@ import VirtualMedia from '@/views/Operations/VirtualMedia';
import Power from '@/views/ResourceManagement/Power';
import i18n from '@/i18n';
+const roles = {
+ administrator: 'Administrator',
+ operator: 'Operator',
+ readonly: 'ReadOnly',
+ noaccess: 'NoAccess',
+};
+
const routes = [
{
path: '/login',
@@ -253,6 +260,7 @@ const routes = [
component: SerialOverLan,
meta: {
title: i18n.t('appPageTitle.serialOverLan'),
+ exclusiveToRoles: [roles.administrator],
},
},
{
@@ -269,6 +277,7 @@ const routes = [
component: VirtualMedia,
meta: {
title: i18n.t('appPageTitle.virtualMedia'),
+ exclusiveToRoles: [roles.administrator],
},
},
{
diff --git a/src/store/modules/Authentication/AuthenticanStore.js b/src/store/modules/Authentication/AuthenticanStore.js
index 88fb54b8..02d6e637 100644
--- a/src/store/modules/Authentication/AuthenticanStore.js
+++ b/src/store/modules/Authentication/AuthenticanStore.js
@@ -58,10 +58,10 @@ const AuthenticationStore = {
.then(() => router.go('/login'))
.catch((error) => console.log(error));
},
- checkPasswordChangeRequired(_, username) {
- api
+ getUserInfo(_, username) {
+ return api
.get(`/redfish/v1/AccountService/Accounts/${username}`)
- .then(({ data: { PasswordChangeRequired } }) => PasswordChangeRequired)
+ .then(({ data }) => data)
.catch((error) => console.log(error));
},
resetStoreState({ state }) {
diff --git a/src/store/modules/GlobalStore.js b/src/store/modules/GlobalStore.js
index 95d7a083..74eb1e80 100644
--- a/src/store/modules/GlobalStore.js
+++ b/src/store/modules/GlobalStore.js
@@ -40,6 +40,7 @@ const GlobalStore = {
: true,
username: localStorage.getItem('storedUsername'),
isAuthorized: true,
+ userPrivilege: null,
},
getters: {
assetTag: (state) => state.assetTag,
@@ -51,6 +52,7 @@ const GlobalStore = {
isUtcDisplay: (state) => state.isUtcDisplay,
username: (state) => state.username,
isAuthorized: (state) => state.isAuthorized,
+ userPrivilege: (state) => state.userPrivilege,
},
mutations: {
setAssetTag: (state, assetTag) => (state.assetTag = assetTag),
@@ -70,6 +72,9 @@ const GlobalStore = {
state.isAuthorized = true;
}, 100);
},
+ setPrivilege: (state, privilege) => {
+ state.userPrivilege = privilege;
+ },
},
actions: {
async getBmcTime({ commit }) {
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index 8d96573a..88d1c7db 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -126,17 +126,17 @@ export default {
localStorage.setItem('storedUsername', username);
this.$store.commit('global/setUsername', username);
this.$store.commit('global/setLanguagePreference', i18n.locale);
- return this.$store.dispatch(
- 'authentication/checkPasswordChangeRequired',
- username
- );
+ return this.$store.dispatch('authentication/getUserInfo', username);
})
- .then((passwordChangeRequired) => {
- if (passwordChangeRequired) {
+ .then(({ PasswordChangeRequired, RoleId }) => {
+ if (PasswordChangeRequired) {
this.$router.push('/change-password');
} else {
this.$router.push('/');
}
+ if (RoleId) {
+ this.$store.commit('global/setPrivilege', RoleId);
+ }
})
.catch((error) => console.log(error))
.finally(() => (this.disableSubmitButton = false));