From 37393810fa1ed2ae69ec05d0b19887e27760d48e Mon Sep 17 00:00:00 2001 From: Yoshie Muranaka Date: Tue, 24 Mar 2020 15:25:24 -0700 Subject: Add SSL Certificates page Adds ability to view, add, replace, and delete SSL certificates in GUI. Signed-off-by: Yoshie Muranaka Change-Id: I5cf9fa7bbd588dfb22f2431eed0b5976ff860703 --- src/store/api.js | 4 +- src/store/index.js | 4 +- .../modules/AccessControl/SslCertificatesStore.js | 158 +++++++++++++++++++++ 3 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 src/store/modules/AccessControl/SslCertificatesStore.js (limited to 'src/store') diff --git a/src/store/api.js b/src/store/api.js index 8fdbdd2f..24a38e4b 100644 --- a/src/store/api.js +++ b/src/store/api.js @@ -29,8 +29,8 @@ export default { delete(path, payload) { return api.delete(path, payload); }, - post(path, payload) { - return api.post(path, payload); + post(path, payload, config) { + return api.post(path, payload, config); }, patch(path, payload) { return api.patch(path, payload); diff --git a/src/store/index.js b/src/store/index.js index 08ada05e..0180213d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -4,6 +4,7 @@ import Vuex from 'vuex'; import GlobalStore from './modules/GlobalStore'; import AuthenticationStore from './modules/Authentication/AuthenticanStore'; import LocalUserManagementStore from './modules/AccessControl/LocalUserMangementStore'; +import SslCertificatesStore from './modules/AccessControl/SslCertificatesStore'; import OverviewStore from './modules/Overview/OverviewStore'; import FirmwareStore from './modules/Configuration/FirmwareStore'; import BootSettingsStore from './modules/Control/BootSettingsStore'; @@ -32,7 +33,8 @@ export default new Vuex.Store({ powerControl: PowerControlStore, networkSettings: NetworkSettingStore, eventLog: EventLogStore, - sensors: SensorsStore + sensors: SensorsStore, + sslCertificates: SslCertificatesStore }, plugins: [WebSocketPlugin] }); diff --git a/src/store/modules/AccessControl/SslCertificatesStore.js b/src/store/modules/AccessControl/SslCertificatesStore.js new file mode 100644 index 00000000..e1758d3c --- /dev/null +++ b/src/store/modules/AccessControl/SslCertificatesStore.js @@ -0,0 +1,158 @@ +import api from '../../api'; +import i18n from '../../../i18n'; + +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: { + getCertificates({ commit }) { + 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') + ); + }); + } + } +}; + +export default SslCertificatesStore; -- cgit v1.2.3