From b440616c23b61166ae6d87839a70eec31bdca235 Mon Sep 17 00:00:00 2001 From: Sandeepa Singh Date: Mon, 26 Jul 2021 15:05:39 +0530 Subject: IA update: Update access and control section This is the fifth commit of the information architecture changes and has the following changes: - The icon for access and control has been updated - Access and control section has been updated to security and access section - Security settings page has been updated to policies page and moved to security and access section - Client sessions page has been updated to sessions page - Local user management page has been updated to user management page - SSL certificates page has been updated to certificates page Signed-off-by: Sandeepa Singh Change-Id: Ie93cee9002742ecf7d33615636f4f159f4395fc4 --- src/store/index.js | 18 +- .../modules/AccessControl/ClientSessionsStore.js | 80 ----- src/store/modules/AccessControl/LdapStore.js | 275 ----------------- .../AccessControl/LocalUserMangementStore.js | 325 --------------------- .../modules/AccessControl/SslCertificatesStore.js | 204 ------------- .../modules/SecurityAndAccess/CertificatesStore.js | 202 +++++++++++++ src/store/modules/SecurityAndAccess/LdapStore.js | 275 +++++++++++++++++ .../modules/SecurityAndAccess/PoliciesStore.js | 87 ++++++ .../modules/SecurityAndAccess/SessionsStore.js | 80 +++++ .../SecurityAndAccess/UserManagementStore.js | 318 ++++++++++++++++++++ .../modules/Settings/SecuritySettingsStore.js | 95 ------ 11 files changed, 971 insertions(+), 988 deletions(-) delete mode 100644 src/store/modules/AccessControl/ClientSessionsStore.js delete mode 100644 src/store/modules/AccessControl/LdapStore.js delete mode 100644 src/store/modules/AccessControl/LocalUserMangementStore.js delete mode 100644 src/store/modules/AccessControl/SslCertificatesStore.js create mode 100644 src/store/modules/SecurityAndAccess/CertificatesStore.js create mode 100644 src/store/modules/SecurityAndAccess/LdapStore.js create mode 100644 src/store/modules/SecurityAndAccess/PoliciesStore.js create mode 100644 src/store/modules/SecurityAndAccess/SessionsStore.js create mode 100644 src/store/modules/SecurityAndAccess/UserManagementStore.js delete mode 100644 src/store/modules/Settings/SecuritySettingsStore.js (limited to 'src/store') diff --git a/src/store/index.js b/src/store/index.js index 2afadd02..608a0270 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -3,10 +3,10 @@ import Vuex from 'vuex'; import GlobalStore from './modules/GlobalStore'; import AuthenticationStore from './modules/Authentication/AuthenticanStore'; -import ClientSessions from './modules/AccessControl/ClientSessionsStore'; -import LdapStore from './modules/AccessControl/LdapStore'; -import LocalUserManagementStore from './modules/AccessControl/LocalUserMangementStore'; -import SslCertificatesStore from './modules/AccessControl/SslCertificatesStore'; +import SessionsStore from './modules/SecurityAndAccess/SessionsStore'; +import LdapStore from './modules/SecurityAndAccess/LdapStore'; +import UserManagementStore from './modules/SecurityAndAccess/UserManagementStore'; +import CertificatesStore from './modules/SecurityAndAccess/CertificatesStore'; import FirmwareStore from './modules/Operations/FirmwareStore'; import BootSettingsStore from './modules/Operations/BootSettingsStore'; import ControlStore from './modules/Operations/ControlStore'; @@ -24,7 +24,7 @@ import ChassisStore from './modules/HardwareStatus/ChassisStore'; import BmcStore from './modules/HardwareStatus/BmcStore'; import ProcessorStore from './modules/HardwareStatus/ProcessorStore'; import PostCodeLogsStore from './modules/Logs/PostCodeLogsStore'; -import SecuritySettingsStore from './modules/Settings/SecuritySettingsStore'; +import PoliciesStore from './modules/SecurityAndAccess/PoliciesStore'; import FactoryResetStore from './modules/Operations/FactoryResetStore'; import WebSocketPlugin from './plugins/WebSocketPlugin'; @@ -40,10 +40,10 @@ export default new Vuex.Store({ modules: { global: GlobalStore, authentication: AuthenticationStore, - clientSessions: ClientSessions, + sessions: SessionsStore, dateTime: DateTimeStore, ldap: LdapStore, - localUsers: LocalUserManagementStore, + userManagement: UserManagementStore, firmware: FirmwareStore, serverBootSettings: BootSettingsStore, controls: ControlStore, @@ -53,8 +53,8 @@ export default new Vuex.Store({ network: NetworkStore, eventLog: EventLogStore, sensors: SensorsStore, - sslCertificates: SslCertificatesStore, serverLed: ServerLedStore, + certificates: CertificatesStore, system: SystemStore, memory: MemoryStore, fan: FanStore, @@ -63,7 +63,7 @@ export default new Vuex.Store({ processors: ProcessorStore, postCodeLogs: PostCodeLogsStore, virtualMedia: VirtualMediaStore, - securitySettings: SecuritySettingsStore, + policies: PoliciesStore, factoryReset: FactoryResetStore, }, plugins: [WebSocketPlugin], diff --git a/src/store/modules/AccessControl/ClientSessionsStore.js b/src/store/modules/AccessControl/ClientSessionsStore.js deleted file mode 100644 index 4295d578..00000000 --- a/src/store/modules/AccessControl/ClientSessionsStore.js +++ /dev/null @@ -1,80 +0,0 @@ -import api, { getResponseCount } from '@/store/api'; -import i18n from '@/i18n'; - -const ClientSessionsStore = { - namespaced: true, - state: { - allConnections: [], - }, - getters: { - allConnections: (state) => state.allConnections, - }, - mutations: { - setAllConnections: (state, allConnections) => - (state.allConnections = allConnections), - }, - actions: { - async getClientSessionsData({ commit }) { - return await api - .get('/redfish/v1/SessionService/Sessions') - .then((response) => - response.data.Members.map((sessionLogs) => sessionLogs['@odata.id']) - ) - .then((sessionUris) => - api.all(sessionUris.map((sessionUri) => api.get(sessionUri))) - ) - .then((sessionUris) => { - const allConnectionsData = sessionUris.map((sessionUri) => { - return { - clientID: sessionUri.data?.Oem?.OpenBMC.ClientID, - username: sessionUri.data?.UserName, - ipAddress: sessionUri.data?.ClientOriginIPAddress, - uri: sessionUri.data['@odata.id'], - }; - }); - commit('setAllConnections', allConnectionsData); - }) - .catch((error) => { - console.log('Client Session Data:', error); - }); - }, - async disconnectSessions({ dispatch }, uris = []) { - const promises = uris.map((uri) => - api.delete(uri).catch((error) => { - console.log(error); - return error; - }) - ); - return await api - .all(promises) - .then((response) => { - dispatch('getClientSessionsData'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - const toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageClientSessions.toast.successDelete', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageClientSessions.toast.errorDelete', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - return toastMessages; - }) - ); - }, - }, -}; -export default ClientSessionsStore; diff --git a/src/store/modules/AccessControl/LdapStore.js b/src/store/modules/AccessControl/LdapStore.js deleted file mode 100644 index 5aa31c2d..00000000 --- a/src/store/modules/AccessControl/LdapStore.js +++ /dev/null @@ -1,275 +0,0 @@ -import api from '@/store/api'; -import i18n from '@/i18n'; -import { find } from 'lodash'; - -const LdapStore = { - namespaced: true, - state: { - isServiceEnabled: null, - ldap: { - serviceEnabled: null, - serviceAddress: null, - bindDn: null, - baseDn: null, - userAttribute: null, - groupsAttribute: null, - roleGroups: [], - }, - activeDirectory: { - serviceEnabled: null, - serviceAddress: null, - bindDn: null, - baseDn: null, - userAttribute: null, - groupsAttribute: null, - roleGroups: [], - }, - }, - getters: { - isServiceEnabled: (state) => state.isServiceEnabled, - ldap: (state) => state.ldap, - activeDirectory: (state) => state.activeDirectory, - isActiveDirectoryEnabled: (state) => { - return state.activeDirectory.serviceEnabled; - }, - enabledRoleGroups: (state, getters) => { - const serviceType = getters.isActiveDirectoryEnabled - ? 'activeDirectory' - : 'ldap'; - return state[serviceType].roleGroups; - }, - }, - mutations: { - setServiceEnabled: (state, serviceEnabled) => - (state.isServiceEnabled = serviceEnabled), - setLdapProperties: ( - state, - { - ServiceEnabled, - ServiceAddresses = [], - Authentication = {}, - LDAPService: { - SearchSettings: { - BaseDistinguishedNames = [], - UsernameAttribute, - GroupsAttribute, - } = {}, - } = {}, - RemoteRoleMapping = [], - } - ) => { - state.ldap.serviceAddress = ServiceAddresses[0]; - state.ldap.serviceEnabled = ServiceEnabled; - state.ldap.baseDn = BaseDistinguishedNames[0]; - state.ldap.bindDn = Authentication.Username; - state.ldap.userAttribute = UsernameAttribute; - state.ldap.groupsAttribute = GroupsAttribute; - state.ldap.roleGroups = RemoteRoleMapping; - }, - setActiveDirectoryProperties: ( - state, - { - ServiceEnabled, - ServiceAddresses = [], - Authentication = {}, - LDAPService: { - SearchSettings: { - BaseDistinguishedNames = [], - UsernameAttribute, - GroupsAttribute, - } = {}, - } = {}, - RemoteRoleMapping = [], - } - ) => { - state.activeDirectory.serviceEnabled = ServiceEnabled; - state.activeDirectory.serviceAddress = ServiceAddresses[0]; - state.activeDirectory.bindDn = Authentication.Username; - state.activeDirectory.baseDn = BaseDistinguishedNames[0]; - state.activeDirectory.userAttribute = UsernameAttribute; - state.activeDirectory.groupsAttribute = GroupsAttribute; - state.activeDirectory.roleGroups = RemoteRoleMapping; - }, - }, - actions: { - async getAccountSettings({ commit }) { - return await api - .get('/redfish/v1/AccountService') - .then(({ data: { LDAP = {}, ActiveDirectory = {} } }) => { - const ldapEnabled = LDAP.ServiceEnabled; - const activeDirectoryEnabled = ActiveDirectory.ServiceEnabled; - - commit('setServiceEnabled', ldapEnabled || activeDirectoryEnabled); - commit('setLdapProperties', LDAP); - commit('setActiveDirectoryProperties', ActiveDirectory); - }) - .catch((error) => console.log(error)); - }, - async saveLdapSettings({ state, dispatch }, properties) { - const data = { LDAP: properties }; - if (state.activeDirectory.serviceEnabled) { - // Disable Active Directory service if enabled - await api.patch('/redfish/v1/AccountService', { - ActiveDirectory: { ServiceEnabled: false }, - }); - } - return await api - .patch('/redfish/v1/AccountService', data) - .then(() => dispatch('getAccountSettings')) - .then(() => i18n.t('pageLdap.toast.successSaveLdapSettings')) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageLdap.toast.errorSaveLdapSettings')); - }); - }, - async saveActiveDirectorySettings({ state, dispatch }, properties) { - const data = { ActiveDirectory: properties }; - if (state.ldap.serviceEnabled) { - // Disable LDAP service if enabled - await api.patch('/redfish/v1/AccountService', { - LDAP: { ServiceEnabled: false }, - }); - } - return await api - .patch('/redfish/v1/AccountService', data) - .then(() => dispatch('getAccountSettings')) - .then(() => i18n.t('pageLdap.toast.successSaveActiveDirectorySettings')) - .catch((error) => { - console.log(error); - throw new Error( - i18n.t('pageLdap.toast.errorSaveActiveDirectorySettings') - ); - }); - }, - async saveAccountSettings( - { dispatch }, - { - serviceEnabled, - serviceAddress, - activeDirectoryEnabled, - bindDn, - bindPassword, - baseDn, - userIdAttribute, - groupIdAttribute, - } - ) { - const data = { - ServiceEnabled: serviceEnabled, - ServiceAddresses: [serviceAddress], - Authentication: { - Username: bindDn, - Password: bindPassword, - }, - LDAPService: { - SearchSettings: { - BaseDistinguishedNames: [baseDn], - }, - }, - }; - if (groupIdAttribute) - data.LDAPService.SearchSettings.GroupsAttribute = groupIdAttribute; - if (userIdAttribute) - data.LDAPService.SearchSettings.UsernameAttribute = userIdAttribute; - - if (activeDirectoryEnabled) { - return await dispatch('saveActiveDirectorySettings', data); - } else { - return await dispatch('saveLdapSettings', data); - } - }, - async addNewRoleGroup( - { dispatch, getters }, - { groupName, groupPrivilege } - ) { - const data = {}; - const enabledRoleGroups = getters['enabledRoleGroups']; - const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; - const RemoteRoleMapping = [ - ...enabledRoleGroups, - { - LocalRole: groupPrivilege, - RemoteGroup: groupName, - }, - ]; - if (isActiveDirectoryEnabled) { - data.ActiveDirectory = { RemoteRoleMapping }; - } else { - data.LDAP = { RemoteRoleMapping }; - } - return await api - .patch('/redfish/v1/AccountService', data) - .then(() => dispatch('getAccountSettings')) - .then(() => - i18n.t('pageLdap.toast.successAddRoleGroup', { - groupName, - }) - ) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageLdap.toast.errorAddRoleGroup')); - }); - }, - async saveRoleGroup({ dispatch, getters }, { groupName, groupPrivilege }) { - const data = {}; - const enabledRoleGroups = getters['enabledRoleGroups']; - const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; - const RemoteRoleMapping = enabledRoleGroups.map((group) => { - if (group.RemoteGroup === groupName) { - return { - RemoteGroup: groupName, - LocalRole: groupPrivilege, - }; - } else { - return {}; - } - }); - if (isActiveDirectoryEnabled) { - data.ActiveDirectory = { RemoteRoleMapping }; - } else { - data.LDAP = { RemoteRoleMapping }; - } - return await api - .patch('/redfish/v1/AccountService', data) - .then(() => dispatch('getAccountSettings')) - .then(() => - i18n.t('pageLdap.toast.successSaveRoleGroup', { groupName }) - ) - .catch((error) => { - console.log(error); - throw new Error(i18n.t('pageLdap.toast.errorSaveRoleGroup')); - }); - }, - async deleteRoleGroup({ dispatch, getters }, { roleGroups = [] }) { - const data = {}; - const enabledRoleGroups = getters['enabledRoleGroups']; - const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; - const RemoteRoleMapping = enabledRoleGroups.map((group) => { - if (find(roleGroups, { groupName: group.RemoteGroup })) { - return null; - } else { - return {}; - } - }); - if (isActiveDirectoryEnabled) { - data.ActiveDirectory = { RemoteRoleMapping }; - } else { - data.LDAP = { RemoteRoleMapping }; - } - return await api - .patch('/redfish/v1/AccountService', data) - .then(() => dispatch('getAccountSettings')) - .then(() => - i18n.tc('pageLdap.toast.successDeleteRoleGroup', roleGroups.length) - ) - .catch((error) => { - console.log(error); - throw new Error( - i18n.tc('pageLdap.toast.errorDeleteRoleGroup', roleGroups.length) - ); - }); - }, - }, -}; - -export default LdapStore; diff --git a/src/store/modules/AccessControl/LocalUserMangementStore.js b/src/store/modules/AccessControl/LocalUserMangementStore.js deleted file mode 100644 index 6bc6ec5d..00000000 --- a/src/store/modules/AccessControl/LocalUserMangementStore.js +++ /dev/null @@ -1,325 +0,0 @@ -import api, { getResponseCount } from '@/store/api'; -import i18n from '@/i18n'; - -const LocalUserManagementStore = { - namespaced: true, - state: { - allUsers: [], - accountRoles: [], - accountLockoutDuration: null, - accountLockoutThreshold: null, - accountMinPasswordLength: null, - accountMaxPasswordLength: null, - }, - getters: { - allUsers(state) { - return state.allUsers; - }, - accountRoles(state) { - return state.accountRoles; - }, - accountSettings(state) { - return { - lockoutDuration: state.accountLockoutDuration, - lockoutThreshold: state.accountLockoutThreshold, - }; - }, - accountPasswordRequirements(state) { - return { - minLength: state.accountMinPasswordLength, - maxLength: state.accountMaxPasswordLength, - }; - }, - }, - mutations: { - setUsers(state, allUsers) { - state.allUsers = allUsers; - }, - setAccountRoles(state, accountRoles) { - state.accountRoles = accountRoles; - }, - setLockoutDuration(state, lockoutDuration) { - state.accountLockoutDuration = lockoutDuration; - }, - setLockoutThreshold(state, lockoutThreshold) { - state.accountLockoutThreshold = lockoutThreshold; - }, - setAccountMinPasswordLength(state, minPasswordLength) { - state.accountMinPasswordLength = minPasswordLength; - }, - setAccountMaxPasswordLength(state, maxPasswordLength) { - state.accountMaxPasswordLength = maxPasswordLength; - }, - }, - actions: { - async getUsers({ commit }) { - return await api - .get('/redfish/v1/AccountService/Accounts') - .then((response) => - response.data.Members.map((user) => user['@odata.id']) - ) - .then((userIds) => api.all(userIds.map((user) => api.get(user)))) - .then((users) => { - const userData = users.map((user) => user.data); - commit('setUsers', userData); - }) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorLoadUsers' - ); - throw new Error(message); - }); - }, - getAccountSettings({ commit }) { - api - .get('/redfish/v1/AccountService') - .then(({ data }) => { - commit('setLockoutDuration', data.AccountLockoutDuration); - commit('setLockoutThreshold', data.AccountLockoutThreshold); - commit('setAccountMinPasswordLength', data.MinPasswordLength); - commit('setAccountMaxPasswordLength', data.MaxPasswordLength); - }) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorLoadAccountSettings' - ); - throw new Error(message); - }); - }, - getAccountRoles({ commit }) { - api - .get('/redfish/v1/AccountService/Roles') - .then(({ data: { Members = [] } = {} }) => { - const roles = Members.map((role) => { - return role['@odata.id'].split('/').pop(); - }); - commit('setAccountRoles', roles); - }) - .catch((error) => console.log(error)); - }, - async createUser({ dispatch }, { username, password, privilege, status }) { - const data = { - UserName: username, - Password: password, - RoleId: privilege, - Enabled: status, - }; - return await api - .post('/redfish/v1/AccountService/Accounts', data) - .then(() => dispatch('getUsers')) - .then(() => - i18n.t('pageLocalUserManagement.toast.successCreateUser', { - username, - }) - ) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorCreateUser', - { username } - ); - throw new Error(message); - }); - }, - async updateUser( - { dispatch }, - { originalUsername, username, password, privilege, status, locked } - ) { - const data = {}; - if (username) data.UserName = username; - if (password) data.Password = password; - if (privilege) data.RoleId = privilege; - if (status !== undefined) data.Enabled = status; - if (locked !== undefined) data.Locked = locked; - return await api - .patch(`/redfish/v1/AccountService/Accounts/${originalUsername}`, data) - .then(() => dispatch('getUsers')) - .then(() => - i18n.t('pageLocalUserManagement.toast.successUpdateUser', { - username: originalUsername, - }) - ) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorUpdateUser', - { username: originalUsername } - ); - throw new Error(message); - }); - }, - async deleteUser({ dispatch }, username) { - return await api - .delete(`/redfish/v1/AccountService/Accounts/${username}`) - .then(() => dispatch('getUsers')) - .then(() => - i18n.t('pageLocalUserManagement.toast.successDeleteUser', { - username, - }) - ) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorDeleteUser', - { username } - ); - throw new Error(message); - }); - }, - async deleteUsers({ dispatch }, users) { - const promises = users.map(({ username }) => { - return api - .delete(`/redfish/v1/AccountService/Accounts/${username}`) - .catch((error) => { - console.log(error); - return error; - }); - }); - return await api - .all(promises) - .then((response) => { - dispatch('getUsers'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - let toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.successBatchDelete', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.errorBatchDelete', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - - return toastMessages; - }) - ); - }, - async enableUsers({ dispatch }, users) { - const data = { - Enabled: true, - }; - const promises = users.map(({ username }) => { - return api - .patch(`/redfish/v1/AccountService/Accounts/${username}`, data) - .catch((error) => { - console.log(error); - return error; - }); - }); - return await api - .all(promises) - .then((response) => { - dispatch('getUsers'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - let toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.successBatchEnable', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.errorBatchEnable', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - - return toastMessages; - }) - ); - }, - async disableUsers({ dispatch }, users) { - const data = { - Enabled: false, - }; - const promises = users.map(({ username }) => { - return api - .patch(`/redfish/v1/AccountService/Accounts/${username}`, data) - .catch((error) => { - console.log(error); - return error; - }); - }); - return await api - .all(promises) - .then((response) => { - dispatch('getUsers'); - return response; - }) - .then( - api.spread((...responses) => { - const { successCount, errorCount } = getResponseCount(responses); - let toastMessages = []; - - if (successCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.successBatchDisable', - successCount - ); - toastMessages.push({ type: 'success', message }); - } - - if (errorCount) { - const message = i18n.tc( - 'pageLocalUserManagement.toast.errorBatchDisable', - errorCount - ); - toastMessages.push({ type: 'error', message }); - } - - return toastMessages; - }) - ); - }, - async saveAccountSettings( - { dispatch }, - { lockoutThreshold, lockoutDuration } - ) { - const data = {}; - if (lockoutThreshold !== undefined) { - data.AccountLockoutThreshold = lockoutThreshold; - } - if (lockoutDuration !== undefined) { - data.AccountLockoutDuration = lockoutDuration; - } - - return await api - .patch('/redfish/v1/AccountService', data) - //GET new settings to update view - .then(() => dispatch('getAccountSettings')) - .then(() => i18n.t('pageLocalUserManagement.toast.successSaveSettings')) - .catch((error) => { - console.log(error); - const message = i18n.t( - 'pageLocalUserManagement.toast.errorSaveSettings' - ); - throw new Error(message); - }); - }, - }, -}; - -export default LocalUserManagementStore; diff --git a/src/store/modules/AccessControl/SslCertificatesStore.js b/src/store/modules/AccessControl/SslCertificatesStore.js deleted file mode 100644 index 752c2124..00000000 --- a/src/store/modules/AccessControl/SslCertificatesStore.js +++ /dev/null @@ -1,204 +0,0 @@ -import api from '@/store/api'; -import i18n from '@/i18n'; - -export const CERTIFICATE_TYPES = [ - { - type: 'HTTPS Certificate', - location: '/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/', - label: i18n.t('pageSslCertificates.httpsCertificate'), - }, - { - type: 'LDAP Certificate', - location: '/redfish/v1/AccountService/LDAP/Certificates/', - label: i18n.t('pageSslCertificates.ldapCertificate'), - }, - { - type: 'TrustStore Certificate', - location: '/redfish/v1/Managers/bmc/Truststore/Certificates/', - // Web UI will show 'CA Certificate' instead of - // 'TrustStore Certificate' after user testing revealed - // the term 'TrustStore Certificate' wasn't recognized/was unfamilar - label: i18n.t('pageSslCertificates.caCertificate'), - }, -]; - -const getCertificateProp = (type, prop) => { - const certificate = CERTIFICATE_TYPES.find( - (certificate) => certificate.type === type - ); - return certificate ? certificate[prop] : null; -}; - -const SslCertificatesStore = { - namespaced: true, - state: { - allCertificates: [], - availableUploadTypes: [], - }, - getters: { - allCertificates: (state) => state.allCertificates, - availableUploadTypes: (state) => state.availableUploadTypes, - }, - mutations: { - setCertificates(state, certificates) { - state.allCertificates = certificates; - }, - setAvailableUploadTypes(state, availableUploadTypes) { - state.availableUploadTypes = availableUploadTypes; - }, - }, - actions: { - async getCertificates({ commit }) { - return await api - .get('/redfish/v1/CertificateService/CertificateLocations') - .then(({ data: { Links: { Certificates } } }) => - Certificates.map((certificate) => certificate['@odata.id']) - ) - .then((certificateLocations) => { - const promises = certificateLocations.map((location) => - api.get(location) - ); - api.all(promises).then( - api.spread((...responses) => { - const certificates = responses.map(({ data }) => { - const { - Name, - ValidNotAfter, - ValidNotBefore, - Issuer = {}, - Subject = {}, - } = data; - return { - type: Name, - location: data['@odata.id'], - certificate: getCertificateProp(Name, 'label'), - issuedBy: Issuer.CommonName, - issuedTo: Subject.CommonName, - validFrom: new Date(ValidNotBefore), - validUntil: new Date(ValidNotAfter), - }; - }); - const availableUploadTypes = CERTIFICATE_TYPES.filter( - ({ type }) => - !certificates - .map((certificate) => certificate.type) - .includes(type) - ); - - commit('setCertificates', certificates); - commit('setAvailableUploadTypes', availableUploadTypes); - }) - ); - }); - }, - async addNewCertificate({ dispatch }, { file, type }) { - return await api - .post(getCertificateProp(type, 'location'), file, { - headers: { 'Content-Type': 'application/x-pem-file' }, - }) - .then(() => dispatch('getCertificates')) - .then(() => - i18n.t('pageSslCertificates.toast.successAddCertificate', { - certificate: getCertificateProp(type, 'label'), - }) - ) - .catch((error) => { - console.log(error); - throw new Error( - i18n.t('pageSslCertificates.toast.errorAddCertificate') - ); - }); - }, - async replaceCertificate( - { dispatch }, - { certificateString, location, type } - ) { - const data = {}; - data.CertificateString = certificateString; - data.CertificateType = 'PEM'; - data.CertificateUri = { '@odata.id': location }; - - return await api - .post( - '/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate', - data - ) - .then(() => dispatch('getCertificates')) - .then(() => - i18n.t('pageSslCertificates.toast.successReplaceCertificate', { - certificate: getCertificateProp(type, 'label'), - }) - ) - .catch((error) => { - console.log(error); - throw new Error( - i18n.t('pageSslCertificates.toast.errorReplaceCertificate') - ); - }); - }, - async deleteCertificate({ dispatch }, { type, location }) { - return await api - .delete(location) - .then(() => dispatch('getCertificates')) - .then(() => - i18n.t('pageSslCertificates.toast.successDeleteCertificate', { - certificate: getCertificateProp(type, 'label'), - }) - ) - .catch((error) => { - console.log(error); - throw new Error( - i18n.t('pageSslCertificates.toast.errorDeleteCertificate') - ); - }); - }, - async generateCsr(_, userData) { - const { - certificateType, - country, - state, - city, - companyName, - companyUnit, - commonName, - keyPairAlgorithm, - keyBitLength, - keyCurveId, - challengePassword, - contactPerson, - emailAddress, - alternateName, - } = userData; - const data = {}; - - data.CertificateCollection = { - '@odata.id': getCertificateProp(certificateType, 'location'), - }; - data.Country = country; - data.State = state; - data.City = city; - data.Organization = companyName; - data.OrganizationalUnit = companyUnit; - data.CommonName = commonName; - data.KeyPairAlgorithm = keyPairAlgorithm; - data.AlternativeNames = alternateName; - - if (keyCurveId) data.KeyCurveId = keyCurveId; - if (keyBitLength) data.KeyBitLength = keyBitLength; - if (challengePassword) data.ChallengePassword = challengePassword; - if (contactPerson) data.ContactPerson = contactPerson; - if (emailAddress) data.Email = emailAddress; - - return await api - .post( - '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR', - data - ) - //TODO: Success response also throws error so - // can't accurately show legitimate error in UI - .catch((error) => console.log(error)); - }, - }, -}; - -export default SslCertificatesStore; diff --git a/src/store/modules/SecurityAndAccess/CertificatesStore.js b/src/store/modules/SecurityAndAccess/CertificatesStore.js new file mode 100644 index 00000000..97241f34 --- /dev/null +++ b/src/store/modules/SecurityAndAccess/CertificatesStore.js @@ -0,0 +1,202 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +export const CERTIFICATE_TYPES = [ + { + type: 'HTTPS Certificate', + location: '/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/', + label: i18n.t('pageCertificates.httpsCertificate'), + }, + { + type: 'LDAP Certificate', + location: '/redfish/v1/AccountService/LDAP/Certificates/', + label: i18n.t('pageCertificates.ldapCertificate'), + }, + { + type: 'TrustStore Certificate', + location: '/redfish/v1/Managers/bmc/Truststore/Certificates/', + // Web UI will show 'CA Certificate' instead of + // 'TrustStore Certificate' after user testing revealed + // the term 'TrustStore Certificate' wasn't recognized/was unfamilar + label: i18n.t('pageCertificates.caCertificate'), + }, +]; + +const getCertificateProp = (type, prop) => { + const certificate = CERTIFICATE_TYPES.find( + (certificate) => certificate.type === type + ); + return certificate ? certificate[prop] : null; +}; + +const CertificatesStore = { + namespaced: true, + state: { + allCertificates: [], + availableUploadTypes: [], + }, + getters: { + allCertificates: (state) => state.allCertificates, + availableUploadTypes: (state) => state.availableUploadTypes, + }, + mutations: { + setCertificates(state, certificates) { + state.allCertificates = certificates; + }, + setAvailableUploadTypes(state, availableUploadTypes) { + state.availableUploadTypes = availableUploadTypes; + }, + }, + actions: { + async getCertificates({ commit }) { + return await api + .get('/redfish/v1/CertificateService/CertificateLocations') + .then(({ data: { Links: { Certificates } } }) => + Certificates.map((certificate) => certificate['@odata.id']) + ) + .then((certificateLocations) => { + const promises = certificateLocations.map((location) => + api.get(location) + ); + api.all(promises).then( + api.spread((...responses) => { + const certificates = responses.map(({ data }) => { + const { + Name, + ValidNotAfter, + ValidNotBefore, + Issuer = {}, + Subject = {}, + } = data; + return { + type: Name, + location: data['@odata.id'], + certificate: getCertificateProp(Name, 'label'), + issuedBy: Issuer.CommonName, + issuedTo: Subject.CommonName, + validFrom: new Date(ValidNotBefore), + validUntil: new Date(ValidNotAfter), + }; + }); + const availableUploadTypes = CERTIFICATE_TYPES.filter( + ({ type }) => + !certificates + .map((certificate) => certificate.type) + .includes(type) + ); + + commit('setCertificates', certificates); + commit('setAvailableUploadTypes', availableUploadTypes); + }) + ); + }); + }, + async addNewCertificate({ dispatch }, { file, type }) { + return await api + .post(getCertificateProp(type, 'location'), file, { + headers: { 'Content-Type': 'application/x-pem-file' }, + }) + .then(() => dispatch('getCertificates')) + .then(() => + i18n.t('pageCertificates.toast.successAddCertificate', { + certificate: getCertificateProp(type, 'label'), + }) + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageCertificates.toast.errorAddCertificate')); + }); + }, + async replaceCertificate( + { dispatch }, + { certificateString, location, type } + ) { + const data = {}; + data.CertificateString = certificateString; + data.CertificateType = 'PEM'; + data.CertificateUri = { '@odata.id': location }; + + return await api + .post( + '/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate', + data + ) + .then(() => dispatch('getCertificates')) + .then(() => + i18n.t('pageCertificates.toast.successReplaceCertificate', { + certificate: getCertificateProp(type, 'label'), + }) + ) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageCertificates.toast.errorReplaceCertificate') + ); + }); + }, + async deleteCertificate({ dispatch }, { type, location }) { + return await api + .delete(location) + .then(() => dispatch('getCertificates')) + .then(() => + i18n.t('pageCertificates.toast.successDeleteCertificate', { + certificate: getCertificateProp(type, 'label'), + }) + ) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageCertificates.toast.errorDeleteCertificate') + ); + }); + }, + async generateCsr(_, userData) { + const { + certificateType, + country, + state, + city, + companyName, + companyUnit, + commonName, + keyPairAlgorithm, + keyBitLength, + keyCurveId, + challengePassword, + contactPerson, + emailAddress, + alternateName, + } = userData; + const data = {}; + + data.CertificateCollection = { + '@odata.id': getCertificateProp(certificateType, 'location'), + }; + data.Country = country; + data.State = state; + data.City = city; + data.Organization = companyName; + data.OrganizationalUnit = companyUnit; + data.CommonName = commonName; + data.KeyPairAlgorithm = keyPairAlgorithm; + data.AlternativeNames = alternateName; + + if (keyCurveId) data.KeyCurveId = keyCurveId; + if (keyBitLength) data.KeyBitLength = keyBitLength; + if (challengePassword) data.ChallengePassword = challengePassword; + if (contactPerson) data.ContactPerson = contactPerson; + if (emailAddress) data.Email = emailAddress; + + return await api + .post( + '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR', + data + ) + //TODO: Success response also throws error so + // can't accurately show legitimate error in UI + .catch((error) => console.log(error)); + }, + }, +}; + +export default CertificatesStore; diff --git a/src/store/modules/SecurityAndAccess/LdapStore.js b/src/store/modules/SecurityAndAccess/LdapStore.js new file mode 100644 index 00000000..5aa31c2d --- /dev/null +++ b/src/store/modules/SecurityAndAccess/LdapStore.js @@ -0,0 +1,275 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; +import { find } from 'lodash'; + +const LdapStore = { + namespaced: true, + state: { + isServiceEnabled: null, + ldap: { + serviceEnabled: null, + serviceAddress: null, + bindDn: null, + baseDn: null, + userAttribute: null, + groupsAttribute: null, + roleGroups: [], + }, + activeDirectory: { + serviceEnabled: null, + serviceAddress: null, + bindDn: null, + baseDn: null, + userAttribute: null, + groupsAttribute: null, + roleGroups: [], + }, + }, + getters: { + isServiceEnabled: (state) => state.isServiceEnabled, + ldap: (state) => state.ldap, + activeDirectory: (state) => state.activeDirectory, + isActiveDirectoryEnabled: (state) => { + return state.activeDirectory.serviceEnabled; + }, + enabledRoleGroups: (state, getters) => { + const serviceType = getters.isActiveDirectoryEnabled + ? 'activeDirectory' + : 'ldap'; + return state[serviceType].roleGroups; + }, + }, + mutations: { + setServiceEnabled: (state, serviceEnabled) => + (state.isServiceEnabled = serviceEnabled), + setLdapProperties: ( + state, + { + ServiceEnabled, + ServiceAddresses = [], + Authentication = {}, + LDAPService: { + SearchSettings: { + BaseDistinguishedNames = [], + UsernameAttribute, + GroupsAttribute, + } = {}, + } = {}, + RemoteRoleMapping = [], + } + ) => { + state.ldap.serviceAddress = ServiceAddresses[0]; + state.ldap.serviceEnabled = ServiceEnabled; + state.ldap.baseDn = BaseDistinguishedNames[0]; + state.ldap.bindDn = Authentication.Username; + state.ldap.userAttribute = UsernameAttribute; + state.ldap.groupsAttribute = GroupsAttribute; + state.ldap.roleGroups = RemoteRoleMapping; + }, + setActiveDirectoryProperties: ( + state, + { + ServiceEnabled, + ServiceAddresses = [], + Authentication = {}, + LDAPService: { + SearchSettings: { + BaseDistinguishedNames = [], + UsernameAttribute, + GroupsAttribute, + } = {}, + } = {}, + RemoteRoleMapping = [], + } + ) => { + state.activeDirectory.serviceEnabled = ServiceEnabled; + state.activeDirectory.serviceAddress = ServiceAddresses[0]; + state.activeDirectory.bindDn = Authentication.Username; + state.activeDirectory.baseDn = BaseDistinguishedNames[0]; + state.activeDirectory.userAttribute = UsernameAttribute; + state.activeDirectory.groupsAttribute = GroupsAttribute; + state.activeDirectory.roleGroups = RemoteRoleMapping; + }, + }, + actions: { + async getAccountSettings({ commit }) { + return await api + .get('/redfish/v1/AccountService') + .then(({ data: { LDAP = {}, ActiveDirectory = {} } }) => { + const ldapEnabled = LDAP.ServiceEnabled; + const activeDirectoryEnabled = ActiveDirectory.ServiceEnabled; + + commit('setServiceEnabled', ldapEnabled || activeDirectoryEnabled); + commit('setLdapProperties', LDAP); + commit('setActiveDirectoryProperties', ActiveDirectory); + }) + .catch((error) => console.log(error)); + }, + async saveLdapSettings({ state, dispatch }, properties) { + const data = { LDAP: properties }; + if (state.activeDirectory.serviceEnabled) { + // Disable Active Directory service if enabled + await api.patch('/redfish/v1/AccountService', { + ActiveDirectory: { ServiceEnabled: false }, + }); + } + return await api + .patch('/redfish/v1/AccountService', data) + .then(() => dispatch('getAccountSettings')) + .then(() => i18n.t('pageLdap.toast.successSaveLdapSettings')) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageLdap.toast.errorSaveLdapSettings')); + }); + }, + async saveActiveDirectorySettings({ state, dispatch }, properties) { + const data = { ActiveDirectory: properties }; + if (state.ldap.serviceEnabled) { + // Disable LDAP service if enabled + await api.patch('/redfish/v1/AccountService', { + LDAP: { ServiceEnabled: false }, + }); + } + return await api + .patch('/redfish/v1/AccountService', data) + .then(() => dispatch('getAccountSettings')) + .then(() => i18n.t('pageLdap.toast.successSaveActiveDirectorySettings')) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageLdap.toast.errorSaveActiveDirectorySettings') + ); + }); + }, + async saveAccountSettings( + { dispatch }, + { + serviceEnabled, + serviceAddress, + activeDirectoryEnabled, + bindDn, + bindPassword, + baseDn, + userIdAttribute, + groupIdAttribute, + } + ) { + const data = { + ServiceEnabled: serviceEnabled, + ServiceAddresses: [serviceAddress], + Authentication: { + Username: bindDn, + Password: bindPassword, + }, + LDAPService: { + SearchSettings: { + BaseDistinguishedNames: [baseDn], + }, + }, + }; + if (groupIdAttribute) + data.LDAPService.SearchSettings.GroupsAttribute = groupIdAttribute; + if (userIdAttribute) + data.LDAPService.SearchSettings.UsernameAttribute = userIdAttribute; + + if (activeDirectoryEnabled) { + return await dispatch('saveActiveDirectorySettings', data); + } else { + return await dispatch('saveLdapSettings', data); + } + }, + async addNewRoleGroup( + { dispatch, getters }, + { groupName, groupPrivilege } + ) { + const data = {}; + const enabledRoleGroups = getters['enabledRoleGroups']; + const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; + const RemoteRoleMapping = [ + ...enabledRoleGroups, + { + LocalRole: groupPrivilege, + RemoteGroup: groupName, + }, + ]; + if (isActiveDirectoryEnabled) { + data.ActiveDirectory = { RemoteRoleMapping }; + } else { + data.LDAP = { RemoteRoleMapping }; + } + return await api + .patch('/redfish/v1/AccountService', data) + .then(() => dispatch('getAccountSettings')) + .then(() => + i18n.t('pageLdap.toast.successAddRoleGroup', { + groupName, + }) + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageLdap.toast.errorAddRoleGroup')); + }); + }, + async saveRoleGroup({ dispatch, getters }, { groupName, groupPrivilege }) { + const data = {}; + const enabledRoleGroups = getters['enabledRoleGroups']; + const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; + const RemoteRoleMapping = enabledRoleGroups.map((group) => { + if (group.RemoteGroup === groupName) { + return { + RemoteGroup: groupName, + LocalRole: groupPrivilege, + }; + } else { + return {}; + } + }); + if (isActiveDirectoryEnabled) { + data.ActiveDirectory = { RemoteRoleMapping }; + } else { + data.LDAP = { RemoteRoleMapping }; + } + return await api + .patch('/redfish/v1/AccountService', data) + .then(() => dispatch('getAccountSettings')) + .then(() => + i18n.t('pageLdap.toast.successSaveRoleGroup', { groupName }) + ) + .catch((error) => { + console.log(error); + throw new Error(i18n.t('pageLdap.toast.errorSaveRoleGroup')); + }); + }, + async deleteRoleGroup({ dispatch, getters }, { roleGroups = [] }) { + const data = {}; + const enabledRoleGroups = getters['enabledRoleGroups']; + const isActiveDirectoryEnabled = getters['isActiveDirectoryEnabled']; + const RemoteRoleMapping = enabledRoleGroups.map((group) => { + if (find(roleGroups, { groupName: group.RemoteGroup })) { + return null; + } else { + return {}; + } + }); + if (isActiveDirectoryEnabled) { + data.ActiveDirectory = { RemoteRoleMapping }; + } else { + data.LDAP = { RemoteRoleMapping }; + } + return await api + .patch('/redfish/v1/AccountService', data) + .then(() => dispatch('getAccountSettings')) + .then(() => + i18n.tc('pageLdap.toast.successDeleteRoleGroup', roleGroups.length) + ) + .catch((error) => { + console.log(error); + throw new Error( + i18n.tc('pageLdap.toast.errorDeleteRoleGroup', roleGroups.length) + ); + }); + }, + }, +}; + +export default LdapStore; diff --git a/src/store/modules/SecurityAndAccess/PoliciesStore.js b/src/store/modules/SecurityAndAccess/PoliciesStore.js new file mode 100644 index 00000000..1e195527 --- /dev/null +++ b/src/store/modules/SecurityAndAccess/PoliciesStore.js @@ -0,0 +1,87 @@ +import api from '@/store/api'; +import i18n from '@/i18n'; + +const PoliciesStore = { + namespaced: true, + state: { + sshProtocolEnabled: false, + ipmiProtocolEnabled: false, + }, + getters: { + sshProtocolEnabled: (state) => state.sshProtocolEnabled, + ipmiProtocolEnabled: (state) => state.ipmiProtocolEnabled, + }, + mutations: { + setSshProtocolEnabled: (state, sshProtocolEnabled) => + (state.sshProtocolEnabled = sshProtocolEnabled), + setIpmiProtocolEnabled: (state, ipmiProtocolEnabled) => + (state.ipmiProtocolEnabled = ipmiProtocolEnabled), + }, + actions: { + async getNetworkProtocolStatus({ commit }) { + return await api + .get('/redfish/v1/Managers/bmc/NetworkProtocol') + .then((response) => { + const sshProtocol = response.data.SSH.ProtocolEnabled; + const ipmiProtocol = response.data.IPMI.ProtocolEnabled; + commit('setSshProtocolEnabled', sshProtocol); + commit('setIpmiProtocolEnabled', ipmiProtocol); + }) + .catch((error) => console.log(error)); + }, + async saveIpmiProtocolState({ commit }, protocolEnabled) { + commit('setIpmiProtocolEnabled', protocolEnabled); + const ipmi = { + IPMI: { + ProtocolEnabled: protocolEnabled, + }, + }; + return await api + .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ipmi) + .then(() => { + if (protocolEnabled) { + return i18n.t('pagePolicies.toast.successIpmiEnabled'); + } else { + return i18n.t('pagePolicies.toast.successIpmiDisabled'); + } + }) + .catch((error) => { + console.log(error); + commit('setIpmiProtocolEnabled', !protocolEnabled); + if (protocolEnabled) { + throw new Error(i18n.t('pagePolicies.toast.errorIpmiEnabled')); + } else { + throw new Error(i18n.t('pagePolicies.toast.errorIpmiDisabled')); + } + }); + }, + async saveSshProtocolState({ commit }, protocolEnabled) { + commit('setSshProtocolEnabled', protocolEnabled); + const ssh = { + SSH: { + ProtocolEnabled: protocolEnabled, + }, + }; + return await api + .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ssh) + .then(() => { + if (protocolEnabled) { + return i18n.t('pagePolicies.toast.successSshEnabled'); + } else { + return i18n.t('pagePolicies.toast.successSshDisabled'); + } + }) + .catch((error) => { + console.log(error); + commit('setSshProtocolEnabled', !protocolEnabled); + if (protocolEnabled) { + throw new Error(i18n.t('pagePolicies.toast.errorSshEnabled')); + } else { + throw new Error(i18n.t('pagePolicies.toast.errorSshDisabled')); + } + }); + }, + }, +}; + +export default PoliciesStore; diff --git a/src/store/modules/SecurityAndAccess/SessionsStore.js b/src/store/modules/SecurityAndAccess/SessionsStore.js new file mode 100644 index 00000000..54607ab6 --- /dev/null +++ b/src/store/modules/SecurityAndAccess/SessionsStore.js @@ -0,0 +1,80 @@ +import api, { getResponseCount } from '@/store/api'; +import i18n from '@/i18n'; + +const SessionsStore = { + namespaced: true, + state: { + allConnections: [], + }, + getters: { + allConnections: (state) => state.allConnections, + }, + mutations: { + setAllConnections: (state, allConnections) => + (state.allConnections = allConnections), + }, + actions: { + async getSessionsData({ commit }) { + return await api + .get('/redfish/v1/SessionService/Sessions') + .then((response) => + response.data.Members.map((sessionLogs) => sessionLogs['@odata.id']) + ) + .then((sessionUris) => + api.all(sessionUris.map((sessionUri) => api.get(sessionUri))) + ) + .then((sessionUris) => { + const allConnectionsData = sessionUris.map((sessionUri) => { + return { + clientID: sessionUri.data?.Oem?.OpenBMC.ClientID, + username: sessionUri.data?.UserName, + ipAddress: sessionUri.data?.ClientOriginIPAddress, + uri: sessionUri.data['@odata.id'], + }; + }); + commit('setAllConnections', allConnectionsData); + }) + .catch((error) => { + console.log('Client Session Data:', error); + }); + }, + async disconnectSessions({ dispatch }, uris = []) { + const promises = uris.map((uri) => + api.delete(uri).catch((error) => { + console.log(error); + return error; + }) + ); + return await api + .all(promises) + .then((response) => { + dispatch('getSessionsData'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + const toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageSessions.toast.successDelete', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageSessions.toast.errorDelete', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + return toastMessages; + }) + ); + }, + }, +}; +export default SessionsStore; diff --git a/src/store/modules/SecurityAndAccess/UserManagementStore.js b/src/store/modules/SecurityAndAccess/UserManagementStore.js new file mode 100644 index 00000000..362f3f64 --- /dev/null +++ b/src/store/modules/SecurityAndAccess/UserManagementStore.js @@ -0,0 +1,318 @@ +import api, { getResponseCount } from '@/store/api'; +import i18n from '@/i18n'; + +const UserManagementStore = { + namespaced: true, + state: { + allUsers: [], + accountRoles: [], + accountLockoutDuration: null, + accountLockoutThreshold: null, + accountMinPasswordLength: null, + accountMaxPasswordLength: null, + }, + getters: { + allUsers(state) { + return state.allUsers; + }, + accountRoles(state) { + return state.accountRoles; + }, + accountSettings(state) { + return { + lockoutDuration: state.accountLockoutDuration, + lockoutThreshold: state.accountLockoutThreshold, + }; + }, + accountPasswordRequirements(state) { + return { + minLength: state.accountMinPasswordLength, + maxLength: state.accountMaxPasswordLength, + }; + }, + }, + mutations: { + setUsers(state, allUsers) { + state.allUsers = allUsers; + }, + setAccountRoles(state, accountRoles) { + state.accountRoles = accountRoles; + }, + setLockoutDuration(state, lockoutDuration) { + state.accountLockoutDuration = lockoutDuration; + }, + setLockoutThreshold(state, lockoutThreshold) { + state.accountLockoutThreshold = lockoutThreshold; + }, + setAccountMinPasswordLength(state, minPasswordLength) { + state.accountMinPasswordLength = minPasswordLength; + }, + setAccountMaxPasswordLength(state, maxPasswordLength) { + state.accountMaxPasswordLength = maxPasswordLength; + }, + }, + actions: { + async getUsers({ commit }) { + return await api + .get('/redfish/v1/AccountService/Accounts') + .then((response) => + response.data.Members.map((user) => user['@odata.id']) + ) + .then((userIds) => api.all(userIds.map((user) => api.get(user)))) + .then((users) => { + const userData = users.map((user) => user.data); + commit('setUsers', userData); + }) + .catch((error) => { + console.log(error); + const message = i18n.t('pageUserManagement.toast.errorLoadUsers'); + throw new Error(message); + }); + }, + getAccountSettings({ commit }) { + api + .get('/redfish/v1/AccountService') + .then(({ data }) => { + commit('setLockoutDuration', data.AccountLockoutDuration); + commit('setLockoutThreshold', data.AccountLockoutThreshold); + commit('setAccountMinPasswordLength', data.MinPasswordLength); + commit('setAccountMaxPasswordLength', data.MaxPasswordLength); + }) + .catch((error) => { + console.log(error); + const message = i18n.t( + 'pageUserManagement.toast.errorLoadAccountSettings' + ); + throw new Error(message); + }); + }, + getAccountRoles({ commit }) { + api + .get('/redfish/v1/AccountService/Roles') + .then(({ data: { Members = [] } = {} }) => { + const roles = Members.map((role) => { + return role['@odata.id'].split('/').pop(); + }); + commit('setAccountRoles', roles); + }) + .catch((error) => console.log(error)); + }, + async createUser({ dispatch }, { username, password, privilege, status }) { + const data = { + UserName: username, + Password: password, + RoleId: privilege, + Enabled: status, + }; + return await api + .post('/redfish/v1/AccountService/Accounts', data) + .then(() => dispatch('getUsers')) + .then(() => + i18n.t('pageUserManagement.toast.successCreateUser', { + username, + }) + ) + .catch((error) => { + console.log(error); + const message = i18n.t('pageUserManagement.toast.errorCreateUser', { + username, + }); + throw new Error(message); + }); + }, + async updateUser( + { dispatch }, + { originalUsername, username, password, privilege, status, locked } + ) { + const data = {}; + if (username) data.UserName = username; + if (password) data.Password = password; + if (privilege) data.RoleId = privilege; + if (status !== undefined) data.Enabled = status; + if (locked !== undefined) data.Locked = locked; + return await api + .patch(`/redfish/v1/AccountService/Accounts/${originalUsername}`, data) + .then(() => dispatch('getUsers')) + .then(() => + i18n.t('pageUserManagement.toast.successUpdateUser', { + username: originalUsername, + }) + ) + .catch((error) => { + console.log(error); + const message = i18n.t('pageUserManagement.toast.errorUpdateUser', { + username: originalUsername, + }); + throw new Error(message); + }); + }, + async deleteUser({ dispatch }, username) { + return await api + .delete(`/redfish/v1/AccountService/Accounts/${username}`) + .then(() => dispatch('getUsers')) + .then(() => + i18n.t('pageUserManagement.toast.successDeleteUser', { + username, + }) + ) + .catch((error) => { + console.log(error); + const message = i18n.t('pageUserManagement.toast.errorDeleteUser', { + username, + }); + throw new Error(message); + }); + }, + async deleteUsers({ dispatch }, users) { + const promises = users.map(({ username }) => { + return api + .delete(`/redfish/v1/AccountService/Accounts/${username}`) + .catch((error) => { + console.log(error); + return error; + }); + }); + return await api + .all(promises) + .then((response) => { + dispatch('getUsers'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + let toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageUserManagement.toast.successBatchDelete', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageUserManagement.toast.errorBatchDelete', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + + return toastMessages; + }) + ); + }, + async enableUsers({ dispatch }, users) { + const data = { + Enabled: true, + }; + const promises = users.map(({ username }) => { + return api + .patch(`/redfish/v1/AccountService/Accounts/${username}`, data) + .catch((error) => { + console.log(error); + return error; + }); + }); + return await api + .all(promises) + .then((response) => { + dispatch('getUsers'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + let toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageUserManagement.toast.successBatchEnable', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageUserManagement.toast.errorBatchEnable', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + + return toastMessages; + }) + ); + }, + async disableUsers({ dispatch }, users) { + const data = { + Enabled: false, + }; + const promises = users.map(({ username }) => { + return api + .patch(`/redfish/v1/AccountService/Accounts/${username}`, data) + .catch((error) => { + console.log(error); + return error; + }); + }); + return await api + .all(promises) + .then((response) => { + dispatch('getUsers'); + return response; + }) + .then( + api.spread((...responses) => { + const { successCount, errorCount } = getResponseCount(responses); + let toastMessages = []; + + if (successCount) { + const message = i18n.tc( + 'pageUserManagement.toast.successBatchDisable', + successCount + ); + toastMessages.push({ type: 'success', message }); + } + + if (errorCount) { + const message = i18n.tc( + 'pageUserManagement.toast.errorBatchDisable', + errorCount + ); + toastMessages.push({ type: 'error', message }); + } + + return toastMessages; + }) + ); + }, + async saveAccountSettings( + { dispatch }, + { lockoutThreshold, lockoutDuration } + ) { + const data = {}; + if (lockoutThreshold !== undefined) { + data.AccountLockoutThreshold = lockoutThreshold; + } + if (lockoutDuration !== undefined) { + data.AccountLockoutDuration = lockoutDuration; + } + + return await api + .patch('/redfish/v1/AccountService', data) + //GET new settings to update view + .then(() => dispatch('getAccountSettings')) + .then(() => i18n.t('pageUserManagement.toast.successSaveSettings')) + .catch((error) => { + console.log(error); + const message = i18n.t('pageUserManagement.toast.errorSaveSettings'); + throw new Error(message); + }); + }, + }, +}; + +export default UserManagementStore; diff --git a/src/store/modules/Settings/SecuritySettingsStore.js b/src/store/modules/Settings/SecuritySettingsStore.js deleted file mode 100644 index 5a885425..00000000 --- a/src/store/modules/Settings/SecuritySettingsStore.js +++ /dev/null @@ -1,95 +0,0 @@ -import api from '@/store/api'; -import i18n from '@/i18n'; - -const SecuritySettingsStore = { - namespaced: true, - state: { - sshProtocolEnabled: false, - ipmiProtocolEnabled: false, - }, - getters: { - sshProtocolEnabled: (state) => state.sshProtocolEnabled, - ipmiProtocolEnabled: (state) => state.ipmiProtocolEnabled, - }, - mutations: { - setSshProtocolEnabled: (state, sshProtocolEnabled) => - (state.sshProtocolEnabled = sshProtocolEnabled), - setIpmiProtocolEnabled: (state, ipmiProtocolEnabled) => - (state.ipmiProtocolEnabled = ipmiProtocolEnabled), - }, - actions: { - async getNetworkProtocolStatus({ commit }) { - return await api - .get('/redfish/v1/Managers/bmc/NetworkProtocol') - .then((response) => { - const sshProtocol = response.data.SSH.ProtocolEnabled; - const ipmiProtocol = response.data.IPMI.ProtocolEnabled; - commit('setSshProtocolEnabled', sshProtocol); - commit('setIpmiProtocolEnabled', ipmiProtocol); - }) - .catch((error) => console.log(error)); - }, - async saveIpmiProtocolState({ commit }, protocolEnabled) { - commit('setIpmiProtocolEnabled', protocolEnabled); - const ipmi = { - IPMI: { - ProtocolEnabled: protocolEnabled, - }, - }; - return await api - .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ipmi) - .then(() => { - if (protocolEnabled) { - return i18n.t('pageSecuritySettings.toast.successIpmiEnabled'); - } else { - return i18n.t('pageSecuritySettings.toast.successIpmiDisabled'); - } - }) - .catch((error) => { - console.log(error); - commit('setIpmiProtocolEnabled', !protocolEnabled); - if (protocolEnabled) { - throw new Error( - i18n.t('pageSecuritySettings.toast.errorIpmiEnabled') - ); - } else { - throw new Error( - i18n.t('pageSecuritySettings.toast.errorIpmiDisabled') - ); - } - }); - }, - async saveSshProtocolState({ commit }, protocolEnabled) { - commit('setSshProtocolEnabled', protocolEnabled); - const ssh = { - SSH: { - ProtocolEnabled: protocolEnabled, - }, - }; - return await api - .patch('/redfish/v1/Managers/bmc/NetworkProtocol', ssh) - .then(() => { - if (protocolEnabled) { - return i18n.t('pageSecuritySettings.toast.successSshEnabled'); - } else { - return i18n.t('pageSecuritySettings.toast.successSshDisabled'); - } - }) - .catch((error) => { - console.log(error); - commit('setSshProtocolEnabled', !protocolEnabled); - if (protocolEnabled) { - throw new Error( - i18n.t('pageSecuritySettings.toast.errorSshEnabled') - ); - } else { - throw new Error( - i18n.t('pageSecuritySettings.toast.errorSshDisabled') - ); - } - }); - }, - }, -}; - -export default SecuritySettingsStore; -- cgit v1.2.3