From af96983b3d7df4c0aba287eed4a8ef582c40e58a Mon Sep 17 00:00:00 2001 From: vmud213 Date: Thu, 11 Jun 2020 11:45:49 +0000 Subject: [PATCH] [Redfish] Provides APIs to add/remove TLS certificate Change-Id: I25c827b5dbd443c2827c0faeb9c92c06e7f778f7 --- proliantutils/ilo/client.py | 18 ++- proliantutils/ilo/operations.py | 20 +++ proliantutils/redfish/redfish.py | 70 +++++++++++ .../redfish/resources/system/bios.py | 14 +++ .../redfish/resources/system/tls_config.py | 62 +++++++++ .../tests/redfish/json_samples/certfile.crt | 24 ++++ .../redfish/json_samples/tls_config.json | 57 +++++++++ .../json_samples/tls_config_settings.json | 66 ++++++++++ .../redfish/resources/system/test_bios.py | 17 +++ .../resources/system/test_tls_config.py | 119 ++++++++++++++++++ proliantutils/tests/redfish/test_redfish.py | 96 ++++++++++++++ 11 files changed, 562 insertions(+), 1 deletion(-) create mode 100644 proliantutils/redfish/resources/system/tls_config.py create mode 100644 proliantutils/tests/redfish/json_samples/certfile.crt create mode 100644 proliantutils/tests/redfish/json_samples/tls_config.json create mode 100644 proliantutils/tests/redfish/json_samples/tls_config_settings.json create mode 100644 proliantutils/tests/redfish/resources/system/test_tls_config.py diff --git a/proliantutils/ilo/client.py b/proliantutils/ilo/client.py index d48fe930..24930a38 100644 --- a/proliantutils/ilo/client.py +++ b/proliantutils/ilo/client.py @@ -121,7 +121,9 @@ SUPPORTED_REDFISH_METHODS = [ 'get_iscsi_initiator_info', 'set_iscsi_initiator_info', 'set_http_boot_url', - 'get_http_boot_url' + 'get_http_boot_url', + 'add_tls_certificate', + 'remove_tls_certificate' ] LOG = log.get_logger(__name__) @@ -879,3 +881,17 @@ class IloClient(operations.IloOperations): :raises: IloError, on an error from iLO. """ return self._call_method('get_available_disk_types') + + def add_tls_certificate(self, cert_file_list): + """Adds the TLS certificate to the iLO + + :raises: IloError, on an error from iLO. + """ + return self._call_method('add_tls_certificate', cert_file_list) + + def remove_tls_certificate(self, fp_list): + """Removes the TLS certificate from the iLO + + :raises: IloError, on an error from iLO. + """ + return self._call_method('remove_tls_certificate', fp_list) diff --git a/proliantutils/ilo/operations.py b/proliantutils/ilo/operations.py index d00c5eff..25e0c6ad 100644 --- a/proliantutils/ilo/operations.py +++ b/proliantutils/ilo/operations.py @@ -533,3 +533,23 @@ class IloOperations(object): not supported on the server. """ raise exception.IloCommandNotSupportedError(ERRMSG) + + def add_tls_certificate(self, cert_file_list): + """Adds the TLS certificate to the iLO + + :param cert_file_list: List of TLS certificate files + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) + + def remove_tls_certificate(self, fp_list): + """Removes the TLS certificate from the iLO + + :param fp_list: List of finger prints of the certificates + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + raise exception.IloCommandNotSupportedError(ERRMSG) diff --git a/proliantutils/redfish/redfish.py b/proliantutils/redfish/redfish.py index 501201f6..7d22189e 100644 --- a/proliantutils/redfish/redfish.py +++ b/proliantutils/redfish/redfish.py @@ -15,6 +15,7 @@ __author__ = 'HPE' import json +import re from six.moves.urllib import parse import sushy @@ -1327,3 +1328,72 @@ class RedfishOperations(operations.IloOperations): {'error': str(e)}) LOG.debug(msg) raise exception.IloError(msg) + + def add_tls_certificate(self, cert_file_list): + """Adds the TLS certificates to the iLO. + + :param cert_file_list: List of TLS certificate files + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + if(self._is_boot_mode_uefi()): + cert_list = [] + for cert_file in cert_file_list: + with open(cert_file, 'r') as f: + data = json.dumps(f.read()) + p = re.sub(r"\"", "", data) + q = re.sub(r"\\n", "\r\n", p) + r = q.rstrip() + cert = {} + cert['X509Certificate'] = r + cert_list.append(cert) + + cert_dict = {} + cert_dict['NewCertificates'] = cert_list + try: + (sushy_system.bios_settings.tls_config. + tls_config_settings.add_tls_certificate(cert_dict)) + except sushy.exceptions.SushyError as e: + msg = (self._("The Redfish controller has failed to upload " + "TLS certificate. Error %(error)s") % + {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + else: + msg = 'TLS certificate cannot be upload in BIOS boot mode' + raise exception.IloCommandNotSupportedInBiosError(msg) + + def remove_tls_certificate(self, fp_list): + """Removes the TLS certificate from the iLO. + + :param fp_list: List of finger prints of the TLS certificates + + :raises: IloError, on an error from iLO. + :raises: IloCommandNotSupportedError, if the command is + not supported on the server. + """ + sushy_system = self._get_sushy_system(PROLIANT_SYSTEM_ID) + if(self._is_boot_mode_uefi()): + cert = {} + del_cert_list = [] + for fp in fp_list: + cert_fp = { + "FingerPrint": fp + } + del_cert_list.append(cert_fp) + cert.update({"DeleteCertificates": del_cert_list}) + try: + (sushy_system.bios_settings.tls_config. + tls_config_settings.remove_tls_certificate(cert)) + except sushy.exceptions.SushyError as e: + msg = (self._("The Redfish controller has failed to remove " + "TLS certificate. Error %(error)s") % + {'error': str(e)}) + LOG.debug(msg) + raise exception.IloError(msg) + else: + msg = 'TLS certificate cannot be removed in BIOS boot mode' + raise exception.IloCommandNotSupportedInBiosError(msg) diff --git a/proliantutils/redfish/resources/system/bios.py b/proliantutils/redfish/resources/system/bios.py index 0d84937a..876451b5 100644 --- a/proliantutils/redfish/resources/system/bios.py +++ b/proliantutils/redfish/resources/system/bios.py @@ -21,6 +21,7 @@ from proliantutils import log from proliantutils.redfish.resources.system import constants as sys_cons from proliantutils.redfish.resources.system import iscsi from proliantutils.redfish.resources.system import mappings +from proliantutils.redfish.resources.system import tls_config from proliantutils.redfish import utils LOG = log.get_logger(__name__) @@ -94,6 +95,19 @@ class BIOSSettings(base.ResourceBase): self, ["Oem", "Hpe", "Links", "iScsi"]), redfish_version=self.redfish_version) + @property + @sushy_utils.cache_it + def tls_config(self): + """Property to provide reference to BIOS TLS configuration instance + + It is calculated once when the first time it is queried. On refresh, + this property gets reset. + """ + return tls_config.TLSConfig( + self._conn, utils.get_subresource_path_by( + self, ["Oem", "Hpe", "Links", "TlsConfig"]), + redfish_version=self.redfish_version) + @property @sushy_utils.cache_it def bios_mappings(self): diff --git a/proliantutils/redfish/resources/system/tls_config.py b/proliantutils/redfish/resources/system/tls_config.py new file mode 100644 index 00000000..c44f08c9 --- /dev/null +++ b/proliantutils/redfish/resources/system/tls_config.py @@ -0,0 +1,62 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sushy.resources import base +from sushy import utils as sushy_utils + +from proliantutils.redfish import utils + + +class TLSConfig(base.ResourceBase): + """Class that represents the TLS Configuration. + + This class extends the functionality of base resource class + from sushy. + """ + + @property + @sushy_utils.cache_it + def tls_config_settings(self): + """Property to provide reference to TLS configuration settings instance + + It is calculated once when the first time it is queried. On refresh, + this property gets reset. + """ + return TLSConfigSettings( + self._conn, + utils.get_subresource_path_by( + self, ["@Redfish.Settings", "SettingsObject"]), + redfish_version=self.redfish_version) + + +class TLSConfigSettings(base.ResourceBase): + """Class that represents the TLS configuration settings. + + This class extends the functionality of base resource class + from sushy. + """ + + def add_tls_certificate(self, cert_data): + """Update tls certificate + + :param data: default tls certs data + """ + self._conn.put(self.path, data=cert_data) + + def remove_tls_certificate(self, cert_data): + """Update tls certificate + + :param data: default tls certs data + """ + self._conn.put(self.path, data=cert_data) diff --git a/proliantutils/tests/redfish/json_samples/certfile.crt b/proliantutils/tests/redfish/json_samples/certfile.crt new file mode 100644 index 00000000..98ec648e --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/certfile.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAPpdOt6Qt3FFMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD +VQQGEwJJTjESMBAGA1UECAwJVGVsYW5nYW5hMRIwEAYDVQQHDAlIeWRlcmFiYWQx +DDAKBgNVBAoMA0hQRTELMAkGA1UECwwCU0cxFDASBgNVBAMMCzE3Mi4xNy4xLjg4 +MSQwIgYJKoZIhvcNAQkBFhV2aW5heS5tLmt1bWFyQGhwZS5jb20wHhcNMTkwNDI0 +MDg1MTI4WhcNMjAwNDIzMDg1MTI4WjCBjDELMAkGA1UEBhMCSU4xEjAQBgNVBAgM +CVRlbGFuZ2FuYTESMBAGA1UEBwwJSHlkZXJhYmFkMQwwCgYDVQQKDANIUEUxCzAJ +BgNVBAsMAlNHMRQwEgYDVQQDDAsxNzIuMTcuMS44ODEkMCIGCSqGSIb3DQEJARYV +dmluYXkubS5rdW1hckBocGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA3afHTbbueWjZMp0w0g4XN5VaGD17kk2fjjpJn0Ltgx2L4SSbEabM/491 +A79wZlr0WSo53IYH7AB2ZA0Ze8ZBML6F4FBhSf6lPoGJN/cHDz5z/bDhNV/KrXLA +uqpghDQS0hiv0KHsk3JXaRz/FM+MmmoKdOWSLCWReGOOIGYwEyaB4CFAXefppTlP +ii0IyzGLMfUERxP3x/UpsR/hejun8QNOKcf5mpTbGbh1Ro+yvoJbeXy7ivkOX9QG +7w8UMzGxFXgQ/U3VvpfY5C1A23wAvX9F+lwNQQ71XfmB9ascC7luzWQ3WqVHVpKh +Ksv0vQ3MM17xEuHzlUrUJJSzltsb+wIDAQABo1AwTjAdBgNVHQ4EFgQUB6xKvLMe +R0JVdSSJZH37aEBh5zQwHwYDVR0jBBgwFoAUB6xKvLMeR0JVdSSJZH37aEBh5zQw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAU3fBFSyx19SMgvBVzelP +NyudGhNKm+3zmKndi2HYdKQWHqg6dMSR9zE8FE6viUgB2v1V+5JpF7NhDbgCaNng +DmC8sm3p6lNpvcEDnPak6759K6yT/k6tlPsZ5GsIGXQhBMJdVw0zJPNHEMIV8SnV +D0SGSG5F+pcPvnQtdLzGl18kIOj0NmjzKnz+l/jBd7bckb7vXM+M/KRmrTE6cLF0 +yB6IQ/UPWiuOIflxSxhSPaVYNWiaRALCJEiIYagoWr6mOUxqCnAdR50Pfwxz7KGI +txLjc4+qa6ZgWEBx3uDQ9ehysBrMOmWg5nXRlO/nbtyFXi+GzZChiNA75fgnb6e/ +YQ== +-----END CERTIFICATE----- diff --git a/proliantutils/tests/redfish/json_samples/tls_config.json b/proliantutils/tests/redfish/json_samples/tls_config.json new file mode 100644 index 00000000..f391861d --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/tls_config.json @@ -0,0 +1,57 @@ + { + "@Redfish.Settings": + { + "@odata.type": "#Settings.v1_0_0.Settings", + "ETag": "", + "Messages": + [ + { + "MessageId": "Base.1.0.Success" + } + ], + "SettingsObject": + { + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/settings/" + }, + "Time": null + }, + "@odata.context": "/redfish/v1/$metadata#HpeTlsConfig.HpeTlsConfig", + "@odata.etag": "W/\"32F7F4DB0288E0E0E071C693DD579D6C\"", + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/", + "@odata.type": "#HpeTlsConfig.v1_0_0.HpeTlsConfig", + "Certificates": + [ + ], + "Ciphers": "AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384", + "DeleteCertificates": + [ + ], + "HostnameCheck": "Disabled", + "Id": "tlsconfig", + "Name": "TLS Current Settings", + "NewCertificates": + [ + ], + "Oem": + { + "Hpe": + { + "@odata.type": "#HpeBiosExt.v2_0_0.HpeBiosExt", + "Links": + { + "BaseConfigs": + { + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/baseconfigs/" + } + }, + "SettingsObject": + { + "UnmodifiedETag": "W/\"28F385EA989AD0D0D053F745E614B9D6\"" + } + } + }, + "ProtocolVersion": "AUTO", + "TlsCaCertificateCount": 0, + "VerifyMode": "PEER" + } + diff --git a/proliantutils/tests/redfish/json_samples/tls_config_settings.json b/proliantutils/tests/redfish/json_samples/tls_config_settings.json new file mode 100644 index 00000000..8ca8eb1f --- /dev/null +++ b/proliantutils/tests/redfish/json_samples/tls_config_settings.json @@ -0,0 +1,66 @@ + + + { + "@Redfish.Settings": + { + "@odata.type": "#Settings.v1_0_0.Settings", + "ETag": "C6239FAE", + "Messages": + [ + { + "MessageId": "Base.1.0.Success" + } + ], + "SettingsObject": + { + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/settings/" + }, + "Time": "2020-06-11T21:20:31+00:00" + }, + "@odata.context": "/redfish/v1/$metadata#HpeTlsConfig.HpeTlsConfig", + "@odata.etag": "W/\"885481367F69969696DE63CCE9D97509\"", + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/", + "@odata.type": "#HpeTlsConfig.v1_0_0.HpeTlsConfig", + "Certificates": + [ + { + "FingerPrint": "FA:3A:68:C7:7E:ED:90:21:D2:FA:3E:54:6B:0C:14:D3:2F:8D:43:50:F7:05:A7:0F:1C:68:35:DB:5C:D2:53:28", + "Issuer": "C=IN, ST=Karnataka, L=Bengaluru, O=HPE, OU=BCOS, CN=Vinay Muddu, emailAddress=vinay.m.kumar@hpe.com", + "SerialNumber": "92DF813625F950E5", + "Subject": "C=IN, ST=Karnataka, L=Bengaluru, O=HPE, OU=BCOS, CN=Vinay Muddu, emailAddress=vinay.m.kumar@hpe.com", + "ValidNotAfter": "06/08/2021 06:40", + "ValidNotBefore": "06/08/2020 06:40" + } + ], + "Ciphers": "AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384", + "DeleteCertificates": + [ + ], + "HostnameCheck": "Disabled", + "Id": "tlsconfig", + "Name": "TLS Current Settings", + "NewCertificates": + [ + ], + "Oem": + { + "Hpe": + { + "@odata.type": "#HpeBiosExt.v2_0_0.HpeBiosExt", + "Links": + { + "BaseConfigs": + { + "@odata.id": "/redfish/v1/systems/1/bios/tlsconfig/baseconfigs/" + } + }, + "SettingsObject": + { + "UnmodifiedETag": "W/\"89BE572CAA977F7F7FE56E1ADBF4F043\"" + } + } + }, + "ProtocolVersion": "AUTO", + "TlsCaCertificateCount": 1, + "VerifyMode": "PEER" + } diff --git a/proliantutils/tests/redfish/resources/system/test_bios.py b/proliantutils/tests/redfish/resources/system/test_bios.py index 7bf30987..6de4e83f 100644 --- a/proliantutils/tests/redfish/resources/system/test_bios.py +++ b/proliantutils/tests/redfish/resources/system/test_bios.py @@ -23,6 +23,7 @@ from proliantutils import exception from proliantutils.redfish.resources.system import bios from proliantutils.redfish.resources.system import constants as sys_cons from proliantutils.redfish.resources.system import iscsi +from proliantutils.redfish.resources.system import tls_config class BIOSSettingsTestCase(testtools.TestCase): @@ -111,6 +112,22 @@ class BIOSSettingsTestCase(testtools.TestCase): self.bios_inst.iscsi_resource) self.conn.get.return_value.json.assert_not_called() + def test_tls_config(self): + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + actual_settings = self.bios_inst.tls_config + self.assertIsInstance(actual_settings, + tls_config.TLSConfig) + self.conn.get.return_value.json.assert_called_once_with() + # reset mock + self.conn.get.return_value.json.reset_mock() + self.assertIs(actual_settings, + self.bios_inst.tls_config) + self.conn.get.return_value.json.assert_not_called() + def test__get_base_configs(self): with open('proliantutils/tests/redfish/' 'json_samples/bios_base_configs.json', 'r') as f: diff --git a/proliantutils/tests/redfish/resources/system/test_tls_config.py b/proliantutils/tests/redfish/resources/system/test_tls_config.py new file mode 100644 index 00000000..845514a0 --- /dev/null +++ b/proliantutils/tests/redfish/resources/system/test_tls_config.py @@ -0,0 +1,119 @@ +# Copyright 2017 Hewlett Packard Enterprise Development LP +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + +import mock +import testtools + +from proliantutils.redfish.resources.system import tls_config + + +class TLSConfigTestCase(testtools.TestCase): + + def setUp(self): + super(TLSConfigTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + + self.tls_config_inst = tls_config.TLSConfig( + self.conn, '/redfish/v1/Systems/1/bios/tlsconfig', + redfish_version='1.0.2') + + def test_tls_config_settings(self): + self.conn.get.return_value.json.reset_mock() + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + actual_settings = self.tls_config_inst.tls_config_settings + self.assertIsInstance(actual_settings, + tls_config.TLSConfigSettings) + self.conn.get.return_value.json.assert_called_once_with() + # reset mock + self.conn.get.return_value.json.reset_mock() + self.assertIs(actual_settings, + self.tls_config_inst.tls_config_settings) + self.conn.get.return_value.json.assert_not_called() + + def test_iscsi_settings_on_refresh(self): + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + actual_settings = self.tls_config_inst.tls_config_settings + self.assertIsInstance(actual_settings, + tls_config.TLSConfigSettings) + + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + + self.tls_config_inst.invalidate() + self.tls_config_inst.refresh(force=False) + + self.assertTrue(actual_settings._is_stale) + + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + self.assertIsInstance(self.tls_config_inst.tls_config_settings, + tls_config.TLSConfigSettings) + self.assertFalse(actual_settings._is_stale) + + +class TLSConfigSettingsTestCase(testtools.TestCase): + + def setUp(self): + super(TLSConfigSettingsTestCase, self).setUp() + self.conn = mock.MagicMock() + with open('proliantutils/tests/redfish/' + 'json_samples/tls_config_settings.json', 'r') as f: + self.conn.get.return_value.json.return_value = ( + json.loads(f.read())) + + self.tls_config_settings_inst = tls_config.TLSConfigSettings( + self.conn, '/redfish/v1/Systems/1/bios/tlsconfig/settings', + redfish_version='1.0.2') + + def test_add_tls_certificate(self): + target_uri = '/redfish/v1/Systems/1/bios/tlsconfig/settings' + cert_data = { + "NewCertificates": [ + { + "X509Certificate": "abc" + } + ] + } + self.tls_config_settings_inst.add_tls_certificate(cert_data) + self.tls_config_settings_inst._conn.put.assert_called_once_with( + target_uri, data=cert_data) + + def test_remove_tls_certificate(self): + target_uri = '/redfish/v1/Systems/1/bios/tlsconfig/settings' + fp = ('FA:3A:68:C7:7E:ED:90:21:D2:FA:3E:54:6B:0C:14:D3:' + '2F:8D:43:50:F7:05:A7:0F:1C:68:35:DB:5C:D2:53:28') + cert = {} + del_cert_list = [{"FingerPrint": fp}] + cert.update({"DeleteCertificates": del_cert_list}) + + self.tls_config_settings_inst.remove_tls_certificate(cert) + self.tls_config_settings_inst._conn.put.assert_called_once_with( + target_uri, data=cert) diff --git a/proliantutils/tests/redfish/test_redfish.py b/proliantutils/tests/redfish/test_redfish.py index d0396c31..ac8ba086 100644 --- a/proliantutils/tests/redfish/test_redfish.py +++ b/proliantutils/tests/redfish/test_redfish.py @@ -2008,3 +2008,99 @@ class RedfishOperationsTestCase(testtools.TestCase): exception.IloError, 'Could not set HTTPS URL on the iLO.', self.rf_client.set_http_boot_url, url, dhcp_enabled) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_add_tls_certificate_bios(self, get_sushy_system_mock, + _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = False + data = { + "NewCertificates": [ + { + "X509Certificate": "Some data" + } + ] + } + + self.assertRaisesRegex( + exception.IloCommandNotSupportedInBiosError, + 'TLS certificate cannot be upload in BIOS boot mode', + self.rf_client.add_tls_certificate, + data) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_add_tls_certificate(self, get_sushy_system_mock, + _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = True + cert_file = 'proliantutils/tests/redfish/json_samples/certfile.crt' + with open('proliantutils/tests/redfish/' + 'json_samples/certfile.crt', 'r') as f: + cert_data = f.read() + + import re + cert_data = cert_data.rstrip() + ref_data = re.sub(r"\n", "\r\n", cert_data) + + data = { + "NewCertificates": [ + { + "X509Certificate": ref_data + } + ] + } + self.rf_client.add_tls_certificate([cert_file]) + + (get_sushy_system_mock.return_value. + bios_settings.tls_config.tls_config_settings. + add_tls_certificate.assert_called_once_with(data)) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_add_tls_certificate_raises_ilo_error(self, get_sushy_system_mock, + _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = True + cert_file = 'proliantutils/tests/redfish/json_samples/certfile.crt' + (get_sushy_system_mock.return_value. + bios_settings.tls_config.tls_config_settings. + add_tls_certificate.side_effect) = ( + sushy.exceptions.SushyError) + + self.assertRaisesRegex( + exception.IloError, + 'The Redfish controller has failed to upload TLS certificate.', + self.rf_client.add_tls_certificate, [cert_file]) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_remove_tls_certificate(self, get_sushy_system_mock, + _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = True + fp = ('FA:3A:68:C7:7E:ED:90:21:D2:FA:3E:54:6B:0C:14:D3:' + '2F:8D:43:50:F7:05:A7:0F:1C:68:35:DB:5C:D2:53:28') + + cert = {} + del_cert_list = [] + cert_fp = { + "FingerPrint": fp + } + del_cert_list.append(cert_fp) + cert.update({"DeleteCertificates": del_cert_list}) + self.rf_client.remove_tls_certificate([fp]) + + (get_sushy_system_mock.return_value. + bios_settings.tls_config.tls_config_settings. + remove_tls_certificate.assert_called_once_with(cert)) + + @mock.patch.object(redfish.RedfishOperations, '_is_boot_mode_uefi') + @mock.patch.object(redfish.RedfishOperations, '_get_sushy_system') + def test_remove_tls_certificate_bios(self, get_sushy_system_mock, + _uefi_boot_mode_mock): + _uefi_boot_mode_mock.return_value = False + fp = ('FA:3A:68:C7:7E:ED:90:21:D2:FA:3E:54:6B:0C:14:D3:' + '2F:8D:43:50:F7:05:A7:0F:1C:68:35:DB:5C:D2:53:28') + + self.assertRaisesRegex( + exception.IloCommandNotSupportedInBiosError, + 'TLS certificate cannot be removed in BIOS boot mode', + self.rf_client.remove_tls_certificate, fp)