Making changes to csr and https certificate
This commit will support creation of https certificate. Change-Id: I58989351b24f7cc2520caff5351ab8a6e553554c
This commit is contained in:
parent
ed00e9ee2e
commit
084b0acb8b
@ -1,3 +1,4 @@
|
||||
# Copyright 2022 Hewlett Packard Enterprise Development LP
|
||||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@ -232,3 +233,14 @@ class MissingAttributeError(RedfishError):
|
||||
class InvalidParameterValueError(RedfishError):
|
||||
message = ('The parameter "%(parameter)s" value "%(value)s" is invalid. '
|
||||
'Valid values are: %(valid_values)s')
|
||||
|
||||
|
||||
class CertificateCreationError(ProliantUtilsException):
|
||||
message = ("Failed to create HTTPS certificate"
|
||||
"reason: %(reason)s")
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
if not message:
|
||||
message = self.message % kwargs
|
||||
|
||||
super(CertificateCreationError, self).__init__(message)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright 2018 Hewlett-Packard Development Company, L.P.
|
||||
# Copyright 2018-2022 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
|
||||
@ -134,7 +134,8 @@ SUPPORTED_REDFISH_METHODS = [
|
||||
'update_authentication_failure_logging',
|
||||
'update_secure_boot',
|
||||
'create_csr',
|
||||
'add_https_certificate'
|
||||
'add_https_certificate',
|
||||
'add_ssl_certificate'
|
||||
]
|
||||
|
||||
LOG = log.get_logger(__name__)
|
||||
@ -1033,6 +1034,7 @@ class IloClient(operations.IloOperations):
|
||||
"""
|
||||
return self._call_method('update_secure_boot', enable, ignore)
|
||||
|
||||
# This method is deprecated, and will be removed in future release.
|
||||
def create_csr(self, path, csr_params):
|
||||
"""Creates the Certificate Signing Request.
|
||||
|
||||
@ -1043,6 +1045,7 @@ class IloClient(operations.IloOperations):
|
||||
"""
|
||||
return self._call_method('create_csr', path, csr_params)
|
||||
|
||||
# This method is deprecated, and will be removed in future release.
|
||||
def add_https_certificate(self, cert_file):
|
||||
"""Adds the signed https certificate to the iLO.
|
||||
|
||||
@ -1050,3 +1053,21 @@ class IloClient(operations.IloOperations):
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
return self._call_method('add_https_certificate', cert_file)
|
||||
|
||||
def add_ssl_certificate(self, csr_params, signed_cert,
|
||||
private_key, pass_phrase):
|
||||
"""Creates CSR and adds the signed SSL certificate to the iLO.
|
||||
|
||||
:param csr_params: A dictionary containing all the necessary
|
||||
information required to create CSR.
|
||||
:param signed_cert: Signed certificate which will be used
|
||||
to sign the created CSR.
|
||||
:param private_key: private key.
|
||||
:param pass_phrase: Pass phrase for the private key.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
return self._call_method('add_ssl_certificate',
|
||||
csr_params=csr_params,
|
||||
signed_cert=signed_cert,
|
||||
private_key=private_key,
|
||||
pass_phrase=pass_phrase)
|
||||
|
@ -1,3 +1,4 @@
|
||||
# Copyright 2022 Hewlett Packard Enterprise Development LP
|
||||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@ -568,3 +569,39 @@ class IloOperations(object):
|
||||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
||||
# This method is deprecated, and will be removed in future release.
|
||||
def create_csr(self, path, csr_params):
|
||||
"""Creates the Certificate Signing Request.
|
||||
|
||||
:param path: directory to store csr file.
|
||||
:param csr_params: A dictionary containing all the necessary
|
||||
information required to create CSR.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
||||
# This method is deprecated, and will be removed in future release.
|
||||
def add_https_certificate(self, cert_file):
|
||||
"""Adds the signed https certificate to the iLO.
|
||||
|
||||
:param cert_file: Signed HTTPS certificate file.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
||||
def add_ssl_certificate(self, csr_params, signed_cert,
|
||||
private_key, pass_phrase):
|
||||
"""Creates CSR and adds the signed SSL certificate to the iLO.
|
||||
|
||||
:param csr_params: A dictionary containing all the necessary
|
||||
information required to create CSR.
|
||||
:param signed_cert: Signed certificate which will be used
|
||||
to sign the created CSR.
|
||||
:param private_key: private key.
|
||||
:param pass_phrase: Pass phrase for the private key.
|
||||
:raises: IloError, on an error from iLO.
|
||||
:raises: IloCommandNotSupportedError, if the command is
|
||||
not supported on the server.
|
||||
"""
|
||||
raise exception.IloCommandNotSupportedError(ERRMSG)
|
||||
|
@ -16,9 +16,8 @@ __author__ = 'HPE'
|
||||
|
||||
from base64 import b64decode
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from OpenSSL.crypto import FILETYPE_ASN1
|
||||
@ -891,10 +890,9 @@ class RedfishOperations(operations.IloOperations):
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def create_csr(self, path, csr_params):
|
||||
def create_csr(self, csr_params):
|
||||
"""Creates the Certificate Signing Request.
|
||||
|
||||
:param path: directory to store csr file.
|
||||
:param csr_params: A dictionary containing all the necessary
|
||||
information required to create CSR.
|
||||
:raises: IloError, on an error from iLO.
|
||||
@ -905,17 +903,12 @@ class RedfishOperations(operations.IloOperations):
|
||||
sushy_man.securityservice.https_certificate_uri.generate_csr(
|
||||
csr_params))
|
||||
|
||||
dir = os.path.join(path, 'cert')
|
||||
|
||||
if not os.path.exists(dir):
|
||||
os.makedirs(dir, 0o755)
|
||||
|
||||
(fd, temp_file) = tempfile.mkstemp(suffix='.csr')
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
f.write(cert_request)
|
||||
|
||||
shutil.copy(temp_file, dir)
|
||||
return temp_file
|
||||
except sushy.exceptions.SushyError as e:
|
||||
msg = (self._('The Redfish controller failed to create the '
|
||||
'certificate signing request. '
|
||||
@ -923,6 +916,71 @@ class RedfishOperations(operations.IloOperations):
|
||||
LOG.debug(msg)
|
||||
raise exception.IloError(msg)
|
||||
|
||||
def add_ssl_certificate(self, csr_params, signed_cert,
|
||||
private_key, pass_phrase):
|
||||
"""Creates CSR and adds the signed SSL certificate to the iLO.
|
||||
|
||||
:param csr_params: A dictionary containing all the necessary
|
||||
information required to create CSR.
|
||||
:param signed_cert: signed certificate which will be used
|
||||
to sign the created CSR.
|
||||
:param private_key: private key.
|
||||
:param pass_phrase: Pass phrase for the private key.
|
||||
:raises: IloError, on an error from iLO.
|
||||
"""
|
||||
csr_file = self.create_csr(csr_params)
|
||||
|
||||
(fd, temp_file) = tempfile.mkstemp(suffix='.ext')
|
||||
(fd, https_cert_file) = tempfile.mkstemp(suffix='.crt')
|
||||
(fd, ss_cert_file) = tempfile.mkstemp(suffix='.crt')
|
||||
|
||||
with open(signed_cert, 'r') as f:
|
||||
data = json.dumps(f.read())
|
||||
p = re.sub(r"\"", "", data)
|
||||
q = re.sub(r"\\n", "\r\n", p).rstrip()
|
||||
|
||||
c_list = re.findall(_CERTIFICATE_PATTERN, q, re.DOTALL)
|
||||
|
||||
if len(c_list) == 0:
|
||||
msg = (self._("No valid certificate in %(cert_file)s.") %
|
||||
{"cert_file": signed_cert})
|
||||
LOG.debug(msg)
|
||||
raise exception.InvalidParameterValueError(msg)
|
||||
|
||||
ss_cert = c_list[0]
|
||||
|
||||
with open(ss_cert_file, 'w') as f:
|
||||
f.write(ss_cert)
|
||||
|
||||
content = [
|
||||
"authorityKeyIdentifier = keyid,issuer\n",
|
||||
"basicConstraints = CA:true,pathlen:1\n",
|
||||
"keyUsage = digitalSignature,keyEncipherment,keyCertSign,cRLSign",
|
||||
"\nextendedKeyUsage = clientAuth,serverAuth\n",
|
||||
"subjectKeyIdentifier = hash"]
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
f.writelines(content)
|
||||
|
||||
cert_cmd = (
|
||||
"openssl x509 -req -days 365 -in %(csr_file)s -extfile"
|
||||
" %(tempfile)s -CA %(cert)s -CAkey %(p_key)s -passin "
|
||||
" pass:%(pphrase)s -CAcreateserial -out %(cert_file)s"
|
||||
% {'csr_file': csr_file, 'tempfile': temp_file,
|
||||
'cert': ss_cert_file, 'p_key': private_key,
|
||||
'pphrase': pass_phrase, 'cert_file': https_cert_file})
|
||||
try:
|
||||
process = subprocess.Popen(cert_cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, shell=True)
|
||||
out, err = process.communicate()
|
||||
except Exception as e:
|
||||
msg = (self._("Failed to create HTTPS certificate. "
|
||||
"error: %(err)s") % {"err": e})
|
||||
LOG.debug(msg)
|
||||
raise exception.CertificateCreationError(msg)
|
||||
|
||||
self.add_https_certificate(https_cert_file)
|
||||
|
||||
def add_https_certificate(self, cert_file):
|
||||
"""Adds the signed https certificate to the iLO.
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# Copyright 2022 Hewlett Packard Enterprise Development LP
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@ -1453,6 +1454,6 @@ class IloRedfishClientTestCase(testtools.TestCase):
|
||||
self.assertEqual('set_iscsi_info',
|
||||
even_more_missed_operations[0])
|
||||
else:
|
||||
self.assertEqual(2, len(even_more_missed_operations))
|
||||
self.assertEqual(len(client.SUPPORTED_REDFISH_METHODS) - 2,
|
||||
self.assertEqual(3, len(even_more_missed_operations))
|
||||
self.assertEqual(len(client.SUPPORTED_REDFISH_METHODS) - 3,
|
||||
validate_method_calls.no_test_cases)
|
||||
|
@ -18,7 +18,6 @@ import builtins
|
||||
import collections
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
@ -2525,9 +2524,7 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
||||
self.rf_client.update_authentication_failure_logging)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
|
||||
@mock.patch.object(os, 'makedirs', autospec=True)
|
||||
@mock.patch.object(redfish, 'shutil', autospec=True)
|
||||
def test_create_csr(self, shutil_mock, makedirs_mock, manager_mock):
|
||||
def test__create_csr(self, manager_mock):
|
||||
data = {
|
||||
"CommonName": '1.1.1.1',
|
||||
"Country": 'IN',
|
||||
@ -2538,13 +2535,12 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
||||
}
|
||||
(manager_mock.return_value.securityservice.https_certificate_uri.
|
||||
generate_csr.return_value) = 'certificate'
|
||||
self.rf_client.create_csr('/httproot', data)
|
||||
self.rf_client.create_csr(data)
|
||||
(manager_mock.return_value.securityservice.https_certificate_uri.
|
||||
generate_csr.assert_called_once_with(data))
|
||||
makedirs_mock.assert_called_once_with('/httproot/cert', 0o755)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
|
||||
def test_create_csr_fail(self, manager_mock):
|
||||
def test__create_csr_fail(self, manager_mock):
|
||||
data = {
|
||||
"CommonName": '1.1.1.1',
|
||||
"Country": 'IN',
|
||||
@ -2559,12 +2555,47 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
||||
msg = ("The Redfish controller failed to create the "
|
||||
"certificate signing request. ")
|
||||
self.assertRaisesRegex(
|
||||
exception.IloError, msg, self.rf_client.create_csr,
|
||||
'/httproot', data)
|
||||
exception.IloError, msg, self.rf_client.create_csr, data)
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, 'create_csr')
|
||||
@mock.patch.object(redfish.RedfishOperations, 'add_https_certificate')
|
||||
@mock.patch.object(builtins, 'open')
|
||||
@mock.patch('subprocess.Popen')
|
||||
def test_add_ssl_certificate(self, subprocess_mock, open_mock,
|
||||
https_cert_mock, create_mock):
|
||||
csr_params = {
|
||||
"CommonName": '1.1.1.1',
|
||||
"Country": 'IN',
|
||||
"State": 'KA',
|
||||
"City": 'blr',
|
||||
"OrgName": 'HPE',
|
||||
"OrgUnit": None
|
||||
}
|
||||
p_key = '/p_key.key'
|
||||
create_mock.return_value = '/tmp/csr_file'
|
||||
data = (
|
||||
"-----BEGIN CERTIFICATE-----\nMIID7TC\nCF"
|
||||
"g879\n-----END CERTIFICATE-----\n"
|
||||
"-----BEGIN CERTIFICATE-----\nKHY8UP\nGH"
|
||||
"f792\n-----END CERTIFICATE-----\n"
|
||||
)
|
||||
|
||||
fd_mock = mock.MagicMock(spec=io.BytesIO)
|
||||
open_mock.return_value = fd_mock
|
||||
fd_mock.__enter__.return_value = fd_mock
|
||||
fd_mock.read.return_value = data
|
||||
process_mock = mock.Mock()
|
||||
attrs = {'communicate.return_value': ('output', 'error')}
|
||||
process_mock.configure_mock(**attrs)
|
||||
subprocess_mock.return_value = process_mock
|
||||
self.rf_client.add_ssl_certificate(csr_params, data, p_key, '1234')
|
||||
subprocess_mock.assert_called_once()
|
||||
https_cert_mock.assert_called_once()
|
||||
create_mock.assert_called_once()
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
|
||||
@mock.patch.object(builtins, 'open')
|
||||
def test_add_https_certificate(self, open_mock, manager_mock):
|
||||
def test__add_https_certificate(self, open_mock, manager_mock):
|
||||
data = (
|
||||
"-----BEGIN CERTIFICATE-----\nMIID7TC\nCF"
|
||||
"g879\n-----END CERTIFICATE-----\n"
|
||||
@ -2591,8 +2622,8 @@ class RedfishOperationsTestCase(testtools.TestCase):
|
||||
|
||||
@mock.patch.object(redfish.RedfishOperations, '_get_sushy_manager')
|
||||
@mock.patch.object(builtins, 'open')
|
||||
def test_add_https_certificate_no_certificate(self, open_mock,
|
||||
manager_mock):
|
||||
def test__add_https_certificate_no_certificate(self, open_mock,
|
||||
manager_mock):
|
||||
data = (
|
||||
"-----UNFORMATED CERTIFICATE-----\nMIID7TC\nCF"
|
||||
"g879\n-----END CERTIFICATE-----\n"
|
||||
|
Loading…
Reference in New Issue
Block a user