diff --git a/api-guide/source/dogtag_setup.rst b/api-guide/source/dogtag_setup.rst index 932f74b71..2d9bcbe3a 100644 --- a/api-guide/source/dogtag_setup.rst +++ b/api-guide/source/dogtag_setup.rst @@ -15,10 +15,10 @@ storage keys that are stored either in a software NSS database or in an HSM. It can serve as a secret store for barbican, and interacts with barbican core through the Dogtag KRA plugin. -In this guide, we will provide instructions on how to set up a basic Dogtag instance -containing a CA and a KRA, and how to configure barbican to use this instance for a -secret store and a certificate plugin. Much more detail about Dogtag, its deployment -options and its administration are available in the `RHCS documentation +In this guide, we will provide instructions on how to set up a basic Dogtag +instance containing a CA and a KRA, and how to configure barbican to use this +instance for a secret store. Much more detail about Dogtag, its deployment +options and its administration are available in the `RHCS documentation `_. **Note:** The code below is taken from the devstack Barbican-Dogtag gate job. You can @@ -166,8 +166,8 @@ created with trusted agent credentials. chown $USER $BARBICAN_CONF_DIR/kra_admin_cert.pem The barbican config file (/etc/barbican/barbican.conf) needs to be modified. -The modifications below set the Dogtag plugins as the only enabled secret store and -certificate plugins. Be sure to restart barbican once these changes are made. +The modifications below set the Dogtag plugins as the only enabled secret store. +Makee sure to restart barbican once these changes are made. Note that the actual hostname of the machine should be used in the script (rather than localhost) because the hostname is used in the subject name for the SSL @@ -189,10 +189,6 @@ server certificate for the CA. namespace = barbican.secretstore.plugin enabled_secretstore_plugins = dogtag_crypto - [certificate] - namespace = barbican.certificate.plugin - enabled_certificate_plugins = dogtag - Testing the Setup ***************** diff --git a/barbican/model/models.py b/barbican/model/models.py index c6346b923..bd47c602b 100644 --- a/barbican/model/models.py +++ b/barbican/model/models.py @@ -52,7 +52,6 @@ class States(object): class OrderType(object): KEY = 'key' ASYMMETRIC = 'asymmetric' - CERTIFICATE = 'certificate' @classmethod def is_valid(cls, order_type): diff --git a/barbican/plugin/dogtag.py b/barbican/plugin/dogtag.py index 8d3d5ac2e..9489beb1a 100644 --- a/barbican/plugin/dogtag.py +++ b/barbican/plugin/dogtag.py @@ -14,30 +14,18 @@ # limitations under the License. import base64 -import copy from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization -import datetime import os from oslo_utils import uuidutils import time import pki - -subcas_available = True -try: - import pki.authority as authority - import pki.feature as feature -except ImportError: - subcas_available = False - -import pki.cert import pki.client import pki.crypto as cryptoutil import pki.key as key import pki.kra import pki.profile -from requests import exceptions as request_exceptions from barbican.common import exception from barbican.common import utils @@ -47,7 +35,6 @@ from barbican import i18n as u # do not need to import every dogtag requirement to generate the # sample config import barbican.plugin.dogtag_config_opts # noqa -import barbican.plugin.interface.certificate_manager as cm import barbican.plugin.interface.secret_store as sstore # reuse the conf object to not call config.new_config() twice @@ -618,734 +605,3 @@ class DogtagKRAPlugin(sstore.SecretStoreBase): ) return twsk - - -def _catch_request_exception(ca_related_function): - def _catch_ca_unavailable(self, *args, **kwargs): - try: - return ca_related_function(self, *args, **kwargs) - except request_exceptions.RequestException: - return cm.ResultDTO( - cm.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST) - - return _catch_ca_unavailable - - -def _catch_enrollment_exceptions(ca_related_function): - def _catch_enrollment_exception(self, *args, **kwargs): - try: - return ca_related_function(self, *args, **kwargs) - except pki.BadRequestException as e: - return cm.ResultDTO( - cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=e.message) - except pki.PKIException as e: - raise cm.CertificateGeneralException( - u._("Exception thrown by enroll_cert: {message}").format( - message=e.message)) - - return _catch_enrollment_exception - - -def _catch_subca_creation_exceptions(ca_related_function): - def _catch_subca_exception(self, *args, **kwargs): - try: - return ca_related_function(self, *args, **kwargs) - except pki.BadRequestException as e: - raise exception.BadSubCACreationRequest(reason=e.message) - except pki.PKIException as e: - raise exception.SubCACreationErrors(reason=e.message) - except request_exceptions.RequestException: - raise exception.SubCACreationErrors( - reason="Unable to connect to CA") - - return _catch_subca_exception - - -def _catch_subca_deletion_exceptions(ca_related_function): - def _catch_subca_exception(self, *args, **kwargs): - try: - return ca_related_function(self, *args, **kwargs) - except pki.ResourceNotFoundException: - LOG.warning("Sub-CA already deleted") - pass - except pki.PKIException as e: - raise exception.SubCADeletionErrors(reason=e.message) - except request_exceptions.RequestException: - raise exception.SubCACreationErrors( - reason="Unable to connect to CA") - - return _catch_subca_exception - - -class DogtagCAPlugin(cm.CertificatePluginBase): - """Implementation of the cert plugin with Dogtag CA as the backend.""" - - # order_metadata fields - PROFILE_ID = "profile_id" - - # plugin_metadata fields - REQUEST_ID = "request_id" - - def __init__(self, conf=CONF): - """Constructor - create the cert clients.""" - connection = create_connection(conf, 'ca') - self.certclient = pki.cert.CertClient(connection) - self.simple_cmc_profile = conf.dogtag_plugin.simple_cmc_profile - self.auto_approved_profiles = conf.dogtag_plugin.auto_approved_profiles - - self.working_dir = conf.dogtag_plugin.plugin_working_dir - if not os.path.isdir(self.working_dir): - os.mkdir(self.working_dir) - - self._expiration = None - self._expiration_delta = conf.dogtag_plugin.ca_expiration_time - self._expiration_data_path = os.path.join(self.working_dir, - "expiration_data.txt") - - self._host_aid_path = os.path.join(self.working_dir, "host_aid.txt") - self._host_aid = None - - if not os.path.isfile(self._expiration_data_path): - self.expiration = datetime.datetime.utcnow() - - global subcas_available - subcas_available = self._are_subcas_enabled_on_backend(connection) - if subcas_available: - self.authority_client = authority.AuthorityClient(connection) - if not os.path.isfile(self._host_aid_path): - self.host_aid = self.get_host_aid() - - @property - def expiration(self): - if self._expiration is None: - try: - with open(self._expiration_data_path) as expiration_fh: - self._expiration = datetime.datetime.strptime( - expiration_fh.read(), - "%Y-%m-%d %H:%M:%S.%f" - ) - except (ValueError, TypeError): - LOG.warning("Invalid data read from expiration file") - self.expiration = datetime.utcnow() - return self._expiration - - @expiration.setter - def expiration(self, val): - with open(self._expiration_data_path, 'w') as expiration_fh: - expiration_fh.write(val.strftime("%Y-%m-%d %H:%M:%S.%f")) - self._expiration = val - - @property - def host_aid(self): - if self._host_aid is None: - with open(self._host_aid_path) as host_aid_fh: - self._host_aid = host_aid_fh.read() - return self._host_aid - - @host_aid.setter - def host_aid(self, val): - if val is not None: - with open(self._host_aid_path, 'w') as host_aid_fh: - host_aid_fh.write(val) - self._host_aid = val - - def _are_subcas_enabled_on_backend(self, connection): - """Check if subca feature is available - - SubCA creation must be supported in both the Dogtag client as well - as on the back-end server. Moreover, it must be enabled on the - backend server. This method sets the subcas_available global variable. - :return: True/False - """ - global subcas_available - if subcas_available: - # subcas are supported in the Dogtag client - try: - feature_client = feature.FeatureClient(connection) - authority_feature = feature_client.get_feature("authority") - if authority_feature.enabled: - LOG.info("Sub-CAs are enabled by Dogtag server") - return True - else: - LOG.info("Sub-CAs are not enabled by Dogtag server") - except (request_exceptions.HTTPError, - pki.ResourceNotFoundException): - LOG.info("Sub-CAs are not supported by Dogtag server") - else: - LOG.info("Sub-CAs are not supported by Dogtag client") - return False - - def _get_request_id(self, order_id, plugin_meta, operation): - request_id = plugin_meta.get(self.REQUEST_ID, None) - if not request_id: - raise cm.CertificateGeneralException( - u._( - "{request} not found for {operation} for " - "order_id {order_id}" - ).format( - request=self.REQUEST_ID, - operation=operation, - order_id=order_id - ) - ) - return request_id - - @_catch_request_exception - def _get_request(self, request_id): - try: - return self.certclient.get_request(request_id) - except pki.RequestNotFoundException: - return None - - @_catch_request_exception - def _get_cert(self, cert_id): - try: - return self.certclient.get_cert(cert_id) - except pki.CertNotFoundException: - return None - - def get_default_ca_name(self): - return "Dogtag CA" - - def get_default_signing_cert(self): - # TODO(alee) Add code to get the signing cert - return None - - def get_default_intermediates(self): - # TODO(alee) Add code to get the cert chain - return None - - def check_certificate_status(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Check the status of a certificate request. - - :param order_id: ID of the order associated with this request - :param order_meta: order_metadata associated with this order - :param plugin_meta: data populated by previous calls for this order, - in particular the request_id - :param barbican_meta_dto: additional data needed to process order. - :return: cm.ResultDTO - """ - request_id = self._get_request_id(order_id, plugin_meta, "checking") - - request = self._get_request(request_id) - if not request: - raise cm.CertificateGeneralException( - u._( - "No request found for request_id {request_id} for " - "order {order_id}" - ).format( - request_id=request_id, - order_id=order_id - ) - ) - - request_status = request.request_status - - if request_status == pki.cert.CertRequestStatus.REJECTED: - return cm.ResultDTO( - cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=request.error_message) - elif request_status == pki.cert.CertRequestStatus.CANCELED: - return cm.ResultDTO( - cm.CertificateStatus.REQUEST_CANCELED) - elif request_status == pki.cert.CertRequestStatus.PENDING: - return cm.ResultDTO( - cm.CertificateStatus.WAITING_FOR_CA) - elif request_status == pki.cert.CertRequestStatus.COMPLETE: - # get the cert - cert_id = request.cert_id - if not cert_id: - raise cm.CertificateGeneralException( - u._( - "Request {request_id} reports status_complete, but no " - "cert_id has been returned" - ).format( - request_id=request_id - ) - ) - - cert = self._get_cert(cert_id) - if not cert: - raise cm.CertificateGeneralException( - u._("Certificate not found for cert_id: {cert_id}").format( - cert_id=cert_id - ) - ) - return cm.ResultDTO( - cm.CertificateStatus.CERTIFICATE_GENERATED, - certificate=cert.encoded, - intermediates=cert.pkcs7_cert_chain) - else: - raise cm.CertificateGeneralException( - u._("Invalid request_status returned by CA")) - - @_catch_request_exception - def issue_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Issue a certificate request to the Dogtag CA - - Call the relevant certificate issuance function depending on the - Barbican defined request type in the order_meta. - - :param order_id: ID of the order associated with this request - :param order_meta: dict containing all the inputs for this request. - This includes the request_type. - :param plugin_meta: Used to store data for status check - :param barbican_meta_dto: additional data needed to process order. - :return: cm.ResultDTO - """ - request_type = order_meta.get( - cm.REQUEST_TYPE, - cm.CertificateRequestType.CUSTOM_REQUEST) - - jump_table = { - cm.CertificateRequestType.SIMPLE_CMC_REQUEST: - self._issue_simple_cmc_request, - cm.CertificateRequestType.FULL_CMC_REQUEST: - self._issue_full_cmc_request, - cm.CertificateRequestType.STORED_KEY_REQUEST: - self._issue_stored_key_request, - cm.CertificateRequestType.CUSTOM_REQUEST: - self._issue_custom_certificate_request - } - - if request_type not in jump_table: - raise DogtagPluginNotSupportedException(u._( - "Dogtag plugin does not support %s request type").format( - request_type)) - - return jump_table[request_type](order_id, order_meta, plugin_meta, - barbican_meta_dto) - - @_catch_enrollment_exceptions - def _issue_simple_cmc_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Issue a simple CMC request to the Dogtag CA. - - :param order_id: - :param order_meta: - :param plugin_meta: - :param barbican_meta_dto: - :return: cm.ResultDTO - """ - if barbican_meta_dto.generated_csr is not None: - csr = barbican_meta_dto.generated_csr - else: - # we expect the CSR to be base64 encoded PEM - # Dogtag CA needs it to be unencoded - csr = base64.b64decode(order_meta.get('request_data')) - - profile_id = order_meta.get('profile', self.simple_cmc_profile) - inputs = { - 'cert_request_type': 'pkcs10', - 'cert_request': csr - } - - return self._issue_certificate_request( - profile_id, inputs, plugin_meta, barbican_meta_dto) - - @_catch_enrollment_exceptions - def _issue_full_cmc_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Issue a full CMC request to the Dogtag CA. - - :param order_id: - :param order_meta: - :param plugin_meta: - :param barbican_meta_dto: - :return: cm.ResultDTO - """ - raise DogtagPluginNotSupportedException(u._( - "Dogtag plugin does not support %s request type").format( - cm.CertificateRequestType.FULL_CMC_REQUEST)) - - @_catch_enrollment_exceptions - def _issue_stored_key_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Issue a simple CMC request to the Dogtag CA. - - :param order_id: - :param order_meta: - :param plugin_meta: - :param barbican_meta_dto: - :return: cm.ResultDTO - """ - return self._issue_simple_cmc_request( - order_id, - order_meta, - plugin_meta, - barbican_meta_dto) - - @_catch_enrollment_exceptions - def _issue_custom_certificate_request(self, order_id, order_meta, - plugin_meta, barbican_meta_dto): - """Issue a custom certificate request to Dogtag CA - - :param order_id: ID of the order associated with this request - :param order_meta: dict containing all the inputs required for a - particular profile. One of these must be the profile_id. - The exact fields (both optional and mandatory) depend on the - profile, but they will be exposed to the user in a method to - expose syntax. Depending on the profile, only the relevant fields - will be populated in the request. All others will be ignored. - :param plugin_meta: Used to store data for status check. - :param barbican_meta_dto: Extra data to aid in processing. - :return: cm.ResultDTO - """ - profile_id = order_meta.get(self.PROFILE_ID, None) - if not profile_id: - return cm.ResultDTO( - cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=u._("No profile_id specified")) - - # we expect the csr to be base64 encoded PEM data. Dogtag CA expects - # PEM data though so we need to decode it. - updated_meta = copy.deepcopy(order_meta) - if 'cert_request' in updated_meta: - updated_meta['cert_request'] = base64.b64decode( - updated_meta['cert_request']) - - return self._issue_certificate_request( - profile_id, updated_meta, plugin_meta, barbican_meta_dto) - - def _issue_certificate_request(self, profile_id, inputs, plugin_meta, - barbican_meta_dto): - """Actually send the cert request to the Dogtag CA - - If the profile_id is one of the auto-approved profiles, then use - the convenience enroll_cert() method to create and approve the request - using the Barbican agent cert credentials. If not, then submit the - request and wait for approval by a CA agent on the Dogtag CA. - - :param profile_id: enrollment profile - :param inputs: dict of request inputs - :param plugin_meta: Used to store data for status check. - :param barbican_meta_dto: Extra data to aid in processing. - :return: cm.ResultDTO - """ - ca_id = barbican_meta_dto.plugin_ca_id or self.get_default_ca_name() - - if profile_id in self.auto_approved_profiles: - if ca_id == self.get_default_ca_name(): - results = self.certclient.enroll_cert(profile_id, inputs) - else: - results = self.certclient.enroll_cert( - profile_id, inputs, ca_id) - return self._process_auto_enrollment_results( - results, plugin_meta, barbican_meta_dto) - else: - request = self.certclient.create_enrollment_request( - profile_id, inputs) - if ca_id == self.get_default_ca_name(): - results = self.certclient.submit_enrollment_request(request) - else: - results = self.certclient.submit_enrollment_request( - request, ca_id) - return self._process_pending_enrollment_results( - results, plugin_meta, barbican_meta_dto) - - def _process_auto_enrollment_results(self, enrollment_results, - plugin_meta, barbican_meta_dto): - """Process results received from Dogtag CA for auto-enrollment - - This processes data from enroll_cert, which submits, approves and - gets the cert issued and returns as a list of CertEnrollment objects. - - :param enrollment_results: list of CertEnrollmentResult objects - :param plugin_meta: metadata dict for storing plugin specific data - :param barbican_meta_dto: object containing extra data to help process - the request - :return: cm.ResultDTO - """ - - # Although it is possible to create multiple certs in an invocation - # of enroll_cert, Barbican cannot handle this case. Assume - # only once cert and request generated for now. - enrollment_result = enrollment_results[0] - request = enrollment_result.request - if not request: - raise cm.CertificateGeneralException( - u._("No request returned in enrollment_results")) - - # store the request_id in the plugin metadata - plugin_meta[self.REQUEST_ID] = request.request_id - - cert = enrollment_result.cert - - return self._create_dto(request.request_status, - request.request_id, - request.error_message, - cert) - - def _process_pending_enrollment_results(self, results, plugin_meta, - barbican_meta_dto): - """Process results received from Dogtag CA for pending enrollment - - This method processes data returned by submit_enrollment_request(), - which creates requests that still need to be approved by an agent. - - :param results: CertRequestInfoCollection object - :param plugin_meta: metadata dict for storing plugin specific data - :param barbican_meta_dto: object containing extra data to help process - the request - :return: cm.ResultDTO - """ - - # Although it is possible to create multiple certs in an invocation - # of enroll_cert, Barbican cannot handle this case. Assume - # only once cert and request generated for now - - cert_request_info = results.cert_request_info_list[0] - status = cert_request_info.request_status - request_id = getattr(cert_request_info, 'request_id', None) - error_message = getattr(cert_request_info, 'error_message', None) - - # store the request_id in the plugin metadata - if request_id: - plugin_meta[self.REQUEST_ID] = request_id - - return self._create_dto(status, request_id, error_message, None) - - def _create_dto(self, request_status, request_id, error_message, cert): - dto = None - if request_status == pki.cert.CertRequestStatus.COMPLETE: - if cert is not None: - # Barbican is expecting base 64 encoded PEM, so we base64 - # encode below. - # - # Currently there is an inconsistency in what Dogtag returns - # for certificates and intermediates. For certs, we return - # PEM, whereas for intermediates, we return headerless PEM. - # This is being addressed in Dogtag ticket: - # https://fedorahosted.org/pki/ticket/1374 - # - # Until this is addressed, simply add the missing headers - cert_chain = (CERT_HEADER + "\r\n" + cert.pkcs7_cert_chain + - CERT_FOOTER) - - dto = cm.ResultDTO(cm.CertificateStatus.CERTIFICATE_GENERATED, - certificate=base64.b64encode(cert.encoded), - intermediates=base64.b64encode(cert_chain)) - else: - raise cm.CertificateGeneralException( - u._("request_id {req_id} returns COMPLETE but no cert " - "returned").format(req_id=request_id)) - - elif request_status == pki.cert.CertRequestStatus.REJECTED: - dto = cm.ResultDTO(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=error_message) - elif request_status == pki.cert.CertRequestStatus.CANCELED: - dto = cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED) - elif request_status == pki.cert.CertRequestStatus.PENDING: - dto = cm.ResultDTO(cm.CertificateStatus.WAITING_FOR_CA) - else: - raise cm.CertificateGeneralException( - u._("Invalid request_status {status} for " - "request_id {request_id}").format( - status=request_status, - request_id=request_id) - ) - - return dto - - def modify_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Modify a certificate request. - - Once a certificate request is generated, it cannot be modified. - The only alternative is to cancel the request (if it has not already - completed) and attempt a fresh enrolment. That is what will be - attempted here. - :param order_id: ID for this order - :param order_meta: order metadata. It is assumed that the newly - modified request data will be present here. - :param plugin_meta: data stored on behalf of the plugin for further - operations - :param barbican_meta_dto: additional data needed to process order. - :return: ResultDTO: - """ - result_dto = self.cancel_certificate_request( - order_id, order_meta, plugin_meta, barbican_meta_dto) - - if result_dto.status == cm.CertificateStatus.REQUEST_CANCELED: - return self.issue_certificate_request( - order_id, order_meta, plugin_meta, barbican_meta_dto) - elif result_dto.status == cm.CertificateStatus.INVALID_OPERATION: - return cm.ResultDTO( - cm.CertificateStatus.INVALID_OPERATION, - status_message=u._( - "Modify request: unable to cancel: " - "{message}").format(message=result_dto.status_message) - ) - else: - # other status (ca_unavailable, client_data_issue) - # return result from cancel operation - return result_dto - - @_catch_request_exception - def cancel_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Cancel a certificate request. - - :param order_id: ID for the order associated with this request - :param order_meta: order metadata fdr this request - :param plugin_meta: data stored by plugin for further processing. - In particular, the request_id - :param barbican_meta_dto: additional data needed to process order. - :return: cm.ResultDTO: - """ - request_id = self._get_request_id(order_id, plugin_meta, "cancelling") - - try: - review_response = self.certclient.review_request(request_id) - self.certclient.cancel_request(request_id, review_response) - - return cm.ResultDTO(cm.CertificateStatus.REQUEST_CANCELED) - except pki.RequestNotFoundException: - return cm.ResultDTO( - cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=u._("no request found for this order")) - except pki.ConflictingOperationException as e: - return cm.ResultDTO( - cm.CertificateStatus.INVALID_OPERATION, - status_message=e.message) - - def supports(self, certificate_spec): - if cm.CA_TYPE in certificate_spec: - return certificate_spec[cm.CA_TYPE] == cm.CA_PLUGIN_TYPE_DOGTAG - - if cm.CA_PLUGIN_TYPE_SYMANTEC in certificate_spec: - # TODO(alee-3) Handle case where SKI is provided - pass - - return True - - def supported_request_types(self): - """Returns the request_types supported by this plugin. - - :returns: a list of the Barbican-core defined request_types - supported by this plugin. - """ - return [cm.CertificateRequestType.SIMPLE_CMC_REQUEST, - cm.CertificateRequestType.STORED_KEY_REQUEST, - cm.CertificateRequestType.CUSTOM_REQUEST] - - def supports_create_ca(self): - """Returns if this plugin and the backend CA supports subCAs - - :return: True/False - """ - return subcas_available - - @_catch_subca_creation_exceptions - def create_ca(self, ca_create_dto): - """Creates a subordinate CA upon request - - :param ca_create_dto: - Data transfer object :class:`CACreateDTO` containing data - required to generate a subordinate CA. This data includes - the subject DN of the new CA signing certificate, a name for - the new CA and a reference to the CA that will issue the new - subordinate CA's signing certificate, - - :return: ca_info: - Dictionary containing the data needed to create a - models.CertificateAuthority object - """ - if not subcas_available: - raise exception.SubCAsNotSupported( - "Subordinate CAs are not supported by this Dogtag CA") - - parent_ca_id = self._get_correct_ca_id(ca_create_dto.parent_ca_id) - ca_data = authority.AuthorityData( - dn=ca_create_dto.subject_dn, - parent_aid=parent_ca_id, - description=ca_create_dto.name) - - new_ca_data = self.authority_client.create_ca(ca_data) - - cert = self.authority_client.get_cert(new_ca_data.aid, "PEM") - chain = self.authority_client.get_chain(new_ca_data.aid, "PEM") - - return { - cm.INFO_NAME: new_ca_data.description, - cm.INFO_CA_SIGNING_CERT: cert, - cm.INFO_EXPIRATION: self.expiration.isoformat(), - cm.INFO_INTERMEDIATES: chain, - cm.PLUGIN_CA_ID: new_ca_data.aid - } - - def _get_correct_ca_id(self, plugin_ca_id): - """Returns the correct authority id - - When the Dogtag plugin updates its CA list, any subcas will - have a plugin_ca_id that matches the authority_id (aid) as - returned from the backend CA. - - For migration purposes, though, ie. migrating from a non-subca - environment to a subca one, we want the host CA to keep the same - plugin_ca_id (which is the default_ca_name) so that no disruption - occurs. Therefore, we need to store the host CA's authority ID - (in get_ca_info) and return it here instead. - """ - if plugin_ca_id == self.get_default_ca_name(): - return self.host_aid - else: - return plugin_ca_id - - @_catch_subca_deletion_exceptions - def delete_ca(self, ca_id): - """Deletes a subordinate CA - - :param ca_id: id for the CA as specified by the plugin - :return: None - """ - if not subcas_available: - raise exception.SubCAsNotSupported( - "Subordinate CAs are not supported by this Dogtag CA") - - # ca must be disabled first - self.authority_client.disable_ca(ca_id) - self.authority_client.delete_ca(ca_id) - - def get_ca_info(self): - if not subcas_available: - return super(DogtagCAPlugin, self).get_ca_info() - - self.expiration = (datetime.datetime.utcnow() + datetime.timedelta( - days=int(self._expiration_delta))) - - ret = {} - cas = self.authority_client.list_cas() - for ca_data in cas.ca_list: - if not ca_data.enabled: - continue - - cert = self.authority_client.get_cert(ca_data.aid, "PEM") - chain = self.authority_client.get_chain(ca_data.aid, "PEM") - ca_info = { - cm.INFO_NAME: ca_data.description, - cm.INFO_CA_SIGNING_CERT: cert, - cm.INFO_INTERMEDIATES: chain, - cm.INFO_EXPIRATION: self.expiration.isoformat() - } - - # handle the migration case. The top level CA should continue - # to work as before - - if ca_data.is_host_authority: - ret[self.get_default_ca_name()] = ca_info - self.host_aid = ca_data.aid - else: - ret[ca_data.aid] = ca_info - - return ret - - def get_host_aid(self): - cas = self.authority_client.list_cas() - for ca_data in cas.ca_list: - if ca_data.is_host_authority: - return ca_data.aid - return None diff --git a/barbican/plugin/dogtag_config_opts.py b/barbican/plugin/dogtag_config_opts.py index a038d538a..8e858b643 100644 --- a/barbican/plugin/dogtag_config_opts.py +++ b/barbican/plugin/dogtag_config_opts.py @@ -18,8 +18,6 @@ from oslo_config import cfg from barbican.common import config from barbican import i18n as u -import barbican.plugin.interface.certificate_manager as cm - CONF = config.new_config() dogtag_plugin_group = cfg.OptGroup(name='dogtag_plugin', @@ -40,18 +38,6 @@ dogtag_plugin_opts = [ cfg.StrOpt('nss_password', help=u._('Password for the NSS certificate databases'), secret=True), - cfg.StrOpt('simple_cmc_profile', - default='caOtherCert', - help=u._('Profile for simple CMC requests')), - cfg.StrOpt('auto_approved_profiles', - default="caServerCert", - help=u._('List of automatically approved enrollment profiles')), - cfg.IntOpt('ca_expiration_time', - default=cm.CA_INFO_DEFAULT_EXPIRATION_DAYS, - help=u._('Time in days for CA entries to expire')), - cfg.StrOpt('plugin_working_dir', - default='/etc/barbican/dogtag', - help=u._('Working directory for Dogtag plugin')), cfg.StrOpt('plugin_name', help=u._('User friendly plugin name'), default='Dogtag KRA'), diff --git a/barbican/plugin/interface/certificate_manager.py b/barbican/plugin/interface/certificate_manager.py deleted file mode 100644 index f9ee8d2ba..000000000 --- a/barbican/plugin/interface/certificate_manager.py +++ /dev/null @@ -1,767 +0,0 @@ -# Copyright (c) 2013-2014 Rackspace, Inc. -# -# 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. - -""" -SSL Certificate resources for Barbican. - -The resources here should be generic across all certificate-related -implementations. Hence do not place vendor-specific content in this module. -""" - -import abc -import datetime - -from oslo_config import cfg -from oslo_utils import encodeutils -from stevedore import named - -from barbican.common import config -from barbican.common import exception -import barbican.common.utils as utils -from barbican import i18n as u -from barbican.model import models -from barbican.model import repositories as repos -from barbican.plugin.util import utils as plugin_utils - -LOG = utils.getLogger(__name__) -CONF = config.new_config() - -# Configuration for certificate processing plugins: -DEFAULT_PLUGIN_NAMESPACE = 'barbican.certificate.plugin' -DEFAULT_PLUGINS = ['simple_certificate'] - -cert_opt_group = cfg.OptGroup(name='certificate', - title='Certificate Plugin Options') -cert_opts = [ - cfg.StrOpt('namespace', - default=DEFAULT_PLUGIN_NAMESPACE, - help=u._('Extension namespace to search for plugins.') - ), - cfg.MultiStrOpt('enabled_certificate_plugins', - default=DEFAULT_PLUGINS, - help=u._('List of certificate plugins to load.') - ) -] -CONF.register_group(cert_opt_group) -CONF.register_opts(cert_opts, group=cert_opt_group) -config.parse_args(CONF) - - -def list_opts(): - yield cert_opt_group, cert_opts - yield cert_event_opt_group, cert_event_opts - - -# Configuration for certificate eventing plugins: -DEFAULT_EVENT_PLUGIN_NAMESPACE = 'barbican.certificate.event.plugin' -DEFAULT_EVENT_PLUGINS = ['simple_certificate_event'] - -cert_event_opt_group = cfg.OptGroup(name='certificate_event', - title='Certificate Event Plugin Options') -cert_event_opts = [ - cfg.StrOpt('namespace', - default=DEFAULT_EVENT_PLUGIN_NAMESPACE, - help=u._('Extension namespace to search for eventing plugins.') - ), - cfg.MultiStrOpt('enabled_certificate_event_plugins', - default=DEFAULT_EVENT_PLUGINS, - help=u._('List of certificate plugins to load.') - ) -] -CONF.register_group(cert_event_opt_group) -CONF.register_opts(cert_event_opts, group=cert_event_opt_group) - - -ERROR_RETRY_MSEC = 300000 -RETRY_MSEC = 3600000 -CA_INFO_DEFAULT_EXPIRATION_DAYS = 1 - -CA_PLUGIN_TYPE_DOGTAG = "dogtag" -CA_PLUGIN_TYPE_SYMANTEC = "symantec" - -# fields to distinguish CA types and subject key identifiers -CA_TYPE = "ca_type" -CA_SUBJECT_KEY_IDENTIFIER = "ca_subject_key_identifier" - -# field to get the certificate request type -REQUEST_TYPE = "request_type" - -# fields for the ca_id, plugin_ca_id -CA_ID = "ca_id" -PLUGIN_CA_ID = "plugin_ca_id" - -# fields for ca_info dict keys -INFO_NAME = "name" -INFO_DESCRIPTION = "description" -INFO_CA_SIGNING_CERT = "ca_signing_certificate" -INFO_INTERMEDIATES = "intermediates" -INFO_EXPIRATION = "expiration" - - -# Singleton to avoid loading the CertificateEventManager plugins more than once -_EVENT_PLUGIN_MANAGER = None - - -class CertificateRequestType(object): - """Constants to define the certificate request type.""" - CUSTOM_REQUEST = "custom" - FULL_CMC_REQUEST = "full-cmc" - SIMPLE_CMC_REQUEST = "simple-cmc" - STORED_KEY_REQUEST = "stored-key" - - -class CertificatePluginNotFound(exception.BarbicanException): - """Raised when no certificate plugin supporting a request is available.""" - def __init__(self, plugin_name=None): - if plugin_name: - message = u._( - 'Certificate plugin "{name}"' - ' not found.').format(name=plugin_name) - else: - message = u._("Certificate plugin not found or configured.") - super(CertificatePluginNotFound, self).__init__(message) - - -class CertificatePluginNotFoundForCAID(exception.BarbicanException): - """Raised when no certificate plugin is available for a CA_ID.""" - def __init__(self, ca_id): - message = u._( - 'Certificate plugin not found for "{ca_id}".').format(ca_id=ca_id) - super(CertificatePluginNotFoundForCAID, self).__init__(message) - - -class CertificateEventPluginNotFound(exception.BarbicanException): - """Raised with no certificate event plugin supporting request.""" - def __init__(self, plugin_name=None): - if plugin_name: - message = u._( - 'Certificate event plugin "{name}" ' - 'not found.').format(name=plugin_name) - else: - message = u._("Certificate event plugin not found.") - super(CertificateEventPluginNotFound, self).__init__(message) - - -class CertificateStatusNotSupported(exception.BarbicanException): - """Raised when cert status returned is unknown.""" - def __init__(self, status): - super(CertificateStatusNotSupported, self).__init__( - u._("Certificate status of {status} not " - "supported").format(status=status) - ) - self.status = status - - -class CertificateGeneralException(exception.BarbicanException): - """Raised when a system fault has occurred.""" - def __init__(self, reason=u._('Unknown')): - super(CertificateGeneralException, self).__init__( - u._('Problem seen during certificate processing - ' - 'Reason: {reason}').format(reason=reason) - ) - self.reason = reason - - -class CertificateStatusClientDataIssue(exception.BarbicanHTTPException): - """Raised when the CA has encountered an issue with request data.""" - - client_message = "" - status_code = 400 - - def __init__(self, reason=u._('Unknown')): - super(CertificateStatusClientDataIssue, self).__init__( - u._('Problem with data in certificate request - ' - 'Reason: {reason}').format(reason=reason) - ) - self.client_message = self.message - - -class CertificateStatusInvalidOperation(exception.BarbicanHTTPException): - """Raised when the CA has encountered an issue with request data.""" - - client_message = "" - status_code = 400 - - def __init__(self, reason=u._('Unknown')): - super(CertificateStatusInvalidOperation, self).__init__( - u._('Invalid operation requested - ' - 'Reason: {reason}').format(reason=reason) - ) - self.client_message = self.message - - -class CertificateEventPluginBase(object, metaclass=abc.ABCMeta): - """Base class for certificate eventing plugins. - - This class is the base plugin contract for issuing certificate related - events from Barbican. - """ - - @abc.abstractmethod - def notify_certificate_is_ready( - self, project_id, order_ref, container_ref): - """Notify that a certificate has been generated and is ready to use. - - :param project_id: Project ID associated with this certificate - :param order_ref: HATEOAS reference URI to the submitted Barbican Order - :param container_ref: HATEOAS reference URI to the Container storing - the certificate - :returns: None - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def notify_ca_is_unavailable( - self, project_id, order_ref, error_msg, retry_in_msec): - """Notify that the certificate authority (CA) isn't available. - - :param project_id: Project ID associated with this order - :param order_ref: HATEOAS reference URI to the submitted Barbican Order - :param error_msg: Error message if it is available - :param retry_in_msec: Delay before attempting to talk to the CA again. - If this is 0, then no attempt will be made. - :returns: None - """ - raise NotImplementedError # pragma: no cover - - -class CertificatePluginBase(object, metaclass=abc.ABCMeta): - """Base class for certificate plugins. - - This class is the base plugin contract for certificates. - """ - - @abc.abstractmethod - def get_default_ca_name(self): - """Get the default CA name - - Provides a default CA name to be returned in the default - get_ca_info() method. If get_ca_info() is overridden (to - support multiple CAs for instance), then this method may not - be called. In that case, just implement this method to return - a dummy variable. - - If this value is used, it should be unique amongst all the CA - plugins. - - :return: The default CA name - :rtype: str - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def get_default_signing_cert(self): - """Get the default CA signing cert - - Provides a default CA signing cert to be returned in the default - get_ca_info() method. If get_ca_info() is overridden (to - support multiple CAs for instance), then this method may not - be called. In that case, just implement this method to return - a dummy variable. - :return: The default CA signing cert - :rtype: str - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def get_default_intermediates(self): - """Get the default CA certificate chain - - Provides a default CA certificate to be returned in the default - get_ca_info() method. If get_ca_info() is overridden (to - support multiple CAs for instance), then this method may not - be called. In that case, just implement this method to return - a dummy variable. - :return: The default CA certificate chain - :rtype: str - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def issue_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Create the initial order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf - :param barbican_meta_dto: - Data transfer object :class:`BarbicanMetaDTO` containing data - added to the request by the Barbican server to provide additional - context for processing, but which are not in - the original request. For example, the plugin_ca_id - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def modify_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Update the order meta-data - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf - :param barbican_meta_dto: - Data transfer object :class:`BarbicanMetaDTO` containing data - added to the request by the Barbican server to provide additional - context for processing, but which are not in - the original request. For example, the plugin_ca_id - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def cancel_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Cancel the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf - :param barbican_meta_dto: - Data transfer object :class:`BarbicanMetaDTO` containing data - added to the request by the Barbican server to provide additional - context for processing, but which are not in - the original request. For example, the plugin_ca_id - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def check_certificate_status(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Check status of the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf - :param barbican_meta_dto: - Data transfer object :class:`BarbicanMetaDTO` containing data - added to the request by the Barbican server to provide additional - context for processing, but which are not in - the original request. For example, the plugin_ca_id - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - raise NotImplementedError # pragma: no cover - - @abc.abstractmethod - def supports(self, certificate_spec): - """Returns if the plugin supports the certificate type. - - :param certificate_spec: Contains details on the certificate to - generate the certificate order - :returns: boolean indicating if the plugin supports the certificate - type - """ - raise NotImplementedError # pragma: no cover - - def supported_request_types(self): - """Returns the request_types supported by this plugin. - - :returns: a list of the Barbican-core defined request_types - supported by this plugin. - """ - return [CertificateRequestType.CUSTOM_REQUEST] # pragma: no cover - - def get_ca_info(self): - """Returns information about the CA(s) supported by this plugin. - - :returns: dictionary indexed by plugin_ca_id. Each entry consists - of a dictionary of key-value pairs. - - An example dictionary containing the current supported attributes - is shown below:: - - { "plugin_ca_id1": { - INFO_NAME : "CA name", - INFO_DESCRIPTION : "CA user friendly description", - INFO_CA_SIGNING_CERT : "base 64 encoded signing cert", - INFO_INTERMEDIATES = "base 64 encoded certificate chain" - INFO_EXPIRATION = "ISO formatted UTC datetime for when this" - "data will become stale" - } - } - - """ - name = self.get_default_ca_name() - expiration = (datetime.datetime.utcnow() + - datetime.timedelta(days=CA_INFO_DEFAULT_EXPIRATION_DAYS)) - - default_info = { - INFO_NAME: name, - INFO_DESCRIPTION: "Certificate Authority - {0}".format(name), - INFO_EXPIRATION: expiration.isoformat() - } - - signing_cert = self.get_default_signing_cert() - if signing_cert is not None: - default_info[INFO_CA_SIGNING_CERT] = signing_cert - - intermediates = self.get_default_intermediates() - if intermediates is not None: - default_info[INFO_INTERMEDIATES] = intermediates - - return {name: default_info} - - def supports_create_ca(self): - """Returns whether the plugin supports on-the-fly generation of subCAs - - :return: boolean, True if supported, defaults to False - """ - return False # pragma: no cover - - def create_ca(self, ca_create_dto): - """Creates a subordinate CA upon request - - This call should only be made if a plugin returns True for - supports_create_ca(). - - :param ca_create_dto: - Data transfer object :class:`CACreateDTO` containing data - required to generate a subordinate CA. This data includes - the subject DN of the new CA signing certificate, a name for - the new CA and a reference to the CA that will issue the new - subordinate CA's signing certificate, - - :return: ca_info: - Dictionary containing the data needed to create a - models.CertificateAuthority object - """ - raise NotImplementedError # pragma: no cover - - def delete_ca(self, ca_id): - """Deletes a subordinate CA - - Like the create_ca call, this should only be made if the plugin - returns True for supports_create_ca() - - :param ca_id: id for the CA as specified by the plugin - :return: None - """ - raise NotImplementedError # pragma: no cover - - -class CACreateDTO(object): - """Class that includes data needed to create a subordinate CA """ - - def __init__(self, name=None, description=None, subject_dn=None, - parent_ca_id=None): - """Creates a new CACreateDTO object. - - :param name: Name for the subordinate CA - :param description: Description for the subordinate CA - :param subject_dn: - Subject DN for the new subordinate CA's signing certificate - :param parent_ca_id: - ID of the CA which is supposed to sign the subordinate CA's - signing certificate. This is ID as known to the plugin - (not the Barbican UUID) - """ - self.name = name - self.description = description - self.subject_dn = subject_dn - self.parent_ca_id = parent_ca_id - - -class CertificateStatus(object): - """Defines statuses for certificate request process. - - In particular: - - CERTIFICATE_GENERATED - Indicates a certificate was created - - WAITING_FOR_CA - Waiting for Certificate authority (CA) to complete order - - CLIENT_DATA_ISSUE_SEEN - Problem was seen with client-provided data - - CA_UNAVAILABLE_FOR_REQUEST - CA was not available, will try again later - - REQUEST_CANCELED - The client or CA cancelled this order - - INVALID_OPERATION - Unexpected error seen processing order - """ - - CERTIFICATE_GENERATED = "certificate generated" - WAITING_FOR_CA = "waiting for CA" - CLIENT_DATA_ISSUE_SEEN = "client data issue seen" - CA_UNAVAILABLE_FOR_REQUEST = "CA unavailable for request" - REQUEST_CANCELED = "request canceled" - INVALID_OPERATION = "invalid operation" - - -class ResultDTO(object): - """Result data transfer object (DTO). - - An object of this type is returned by most certificate plugin methods, and - is used to guide follow on processing and to provide status feedback to - clients. - """ - def __init__(self, status, status_message=None, certificate=None, - intermediates=None, retry_msec=RETRY_MSEC, retry_method=None): - """Creates a new ResultDTO. - - :param status: Status for cert order - :param status_message: Message to explain status type. - :param certificate: Certificate returned from CA to be stored in - container - :param intermediates: Intermediates to be stored in container - :param retry_msec: Number of milliseconds to wait for retry - :param retry_method: Method to be called for retry, if None then retry - the current method - """ - self.status = status - self.status_message = status_message - self.certificate = certificate - self.intermediates = intermediates - self.retry_msec = int(retry_msec) - self.retry_method = retry_method - - -class BarbicanMetaDTO(object): - """Barbican meta data transfer object - - Information needed to process a certificate request that is not specified - in the original request, and written by Barbican core, that is needed - by the plugin to process requests. - """ - - def __init__(self, plugin_ca_id=None, generated_csr=None): - """Creates a new BarbicanMetaDTO. - - :param plugin_ca_id: ca_id as known to the plugin - :param generated_csr: csr generated in the stored-key case - :return: BarbicanMetaDTO - """ - self.plugin_ca_id = plugin_ca_id - self.generated_csr = generated_csr - - -class CertificatePluginManager(named.NamedExtensionManager): - def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}): - self.ca_repo = repos.get_ca_repository() - super(CertificatePluginManager, self).__init__( - conf.certificate.namespace, - conf.certificate.enabled_certificate_plugins, - invoke_on_load=False, # Defer creating plugins to utility below. - invoke_args=invoke_args, - invoke_kwds=invoke_kwargs - ) - - plugin_utils.instantiate_plugins( - self, invoke_args, invoke_kwargs) - - def get_plugin(self, certificate_spec): - """Gets a supporting certificate plugin. - - :param certificate_spec: Contains details on the certificate to - generate the certificate order - :returns: CertificatePluginBase plugin implementation - """ - request_type = certificate_spec.get( - REQUEST_TYPE, - CertificateRequestType.CUSTOM_REQUEST) - - for plugin in plugin_utils.get_active_plugins(self): - supported_request_types = plugin.supported_request_types() - if request_type not in supported_request_types: - continue - - if plugin.supports(certificate_spec): - return plugin - - raise CertificatePluginNotFound() - - def get_plugin_by_name(self, plugin_name): - """Gets a supporting certificate plugin. - - :param plugin_name: Name of the plugin to invoke - :returns: CertificatePluginBase plugin implementation - """ - for plugin in plugin_utils.get_active_plugins(self): - if utils.generate_fullname_for(plugin) == plugin_name: - return plugin - raise CertificatePluginNotFound(plugin_name) - - def get_plugin_by_ca_id(self, ca_id): - """Gets a plugin based on the ca_id. - - :param ca_id: id for CA in the CertificateAuthorities table - :returns: CertificatePluginBase plugin implementation - """ - ca = self.ca_repo.get(ca_id, suppress_exception=True) - if not ca: - raise CertificatePluginNotFoundForCAID(ca_id) - - return self.get_plugin_by_name(ca.plugin_name) - - def refresh_ca_table(self): - """Refreshes the CertificateAuthority table.""" - updates_made = False - for plugin in plugin_utils.get_active_plugins(self): - plugin_name = utils.generate_fullname_for(plugin) - cas, offset, limit, total = self.ca_repo.get_by_create_date( - plugin_name=plugin_name, - suppress_exception=True) - if total < 1: - # if no entries are found, then the plugin has not yet been - # queried or that plugin's entries have expired. - # Most of the time, this will be a no-op for plugins. - self.update_ca_info(plugin) - updates_made = True - if updates_made: - # commit to DB to avoid async issues with different threads - repos.commit() - - def update_ca_info(self, cert_plugin): - """Update the CA info for a particular plugin.""" - - plugin_name = utils.generate_fullname_for(cert_plugin) - try: - new_ca_infos = cert_plugin.get_ca_info() - except Exception as e: - # The plugin gave an invalid CA, log and return - LOG.error("ERROR getting CA from plugin: %s", - encodeutils.exception_to_unicode(e)) - return - - old_cas, offset, limit, total = self.ca_repo.get_by_create_date( - plugin_name=plugin_name, - suppress_exception=True, - show_expired=True) - - if old_cas: - for old_ca in old_cas: - plugin_ca_id = old_ca.plugin_ca_id - if plugin_ca_id not in new_ca_infos.keys(): - # remove CAs that no longer exist - self._delete_ca(old_ca) - else: - # update those that still exist - self.ca_repo.update_entity( - old_ca, - new_ca_infos[plugin_ca_id]) - old_ids = set([ca.plugin_ca_id for ca in old_cas]) - else: - old_ids = set() - - new_ids = set(new_ca_infos.keys()) - - # add new CAs - add_ids = new_ids - old_ids - for add_id in add_ids: - try: - self._add_ca(plugin_name, add_id, new_ca_infos[add_id]) - except Exception as e: - # The plugin gave an invalid CA, log and continue - LOG.error("ERROR adding CA from plugin: %s", - encodeutils.exception_to_unicode(e)) - - def _add_ca(self, plugin_name, plugin_ca_id, ca_info): - parsed_ca = dict(ca_info) - parsed_ca['plugin_name'] = plugin_name - parsed_ca['plugin_ca_id'] = plugin_ca_id - new_ca = models.CertificateAuthority(parsed_ca) - self.ca_repo.create_from(new_ca) - - def _delete_ca(self, ca): - self.ca_repo.delete_entity_by_id(ca.id, None) - - -class _CertificateEventPluginManager(named.NamedExtensionManager, - CertificateEventPluginBase): - """Provides services for certificate event plugins. - - This plugin manager differs from others in that it implements the same - contract as the plugins that it manages. This allows eventing operations - to occur on all installed plugins (with this class acting as a composite - plugin), rather than just eventing via an individual plugin. - - Each time this class is initialized it will load a new instance - of each enabled plugin. This is undesirable, so rather than initializing a - new instance of this class use the get_event_plugin_manager function - at the module level. - """ - def __init__(self, conf=CONF, invoke_args=(), invoke_kwargs={}): - super(_CertificateEventPluginManager, self).__init__( - conf.certificate_event.namespace, - conf.certificate_event.enabled_certificate_event_plugins, - invoke_on_load=False, # Defer creating plugins to utility below. - invoke_args=invoke_args, - invoke_kwds=invoke_kwargs - ) - - plugin_utils.instantiate_plugins( - self, invoke_args, invoke_kwargs) - - def get_plugin_by_name(self, plugin_name): - """Gets a supporting certificate event plugin. - - :returns: CertificateEventPluginBase plugin implementation - """ - for plugin in plugin_utils.get_active_plugins(self): - if utils.generate_fullname_for(plugin) == plugin_name: - return plugin - raise CertificateEventPluginNotFound(plugin_name) - - def notify_certificate_is_ready( - self, project_id, order_ref, container_ref): - self._invoke_certificate_plugins( - 'notify_certificate_is_ready', - project_id, order_ref, container_ref) - - def notify_ca_is_unavailable( - self, project_id, order_ref, error_msg, retry_in_msec): - self._invoke_certificate_plugins( - 'notify_ca_is_unavailable', - project_id, order_ref, error_msg, retry_in_msec) - - def _invoke_certificate_plugins(self, method, *args, **kwargs): - """Invoke same function on plugins as calling function.""" - active_plugins = plugin_utils.get_active_plugins(self) - - if not active_plugins: - raise CertificateEventPluginNotFound() - - for plugin in active_plugins: - getattr(plugin, method)(*args, **kwargs) - - -def get_event_plugin_manager(): - global _EVENT_PLUGIN_MANAGER - if _EVENT_PLUGIN_MANAGER: - return _EVENT_PLUGIN_MANAGER - _EVENT_PLUGIN_MANAGER = _CertificateEventPluginManager() - return _EVENT_PLUGIN_MANAGER diff --git a/barbican/plugin/simple_certificate_manager.py b/barbican/plugin/simple_certificate_manager.py deleted file mode 100644 index 71fb40d99..000000000 --- a/barbican/plugin/simple_certificate_manager.py +++ /dev/null @@ -1,160 +0,0 @@ -# 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. - -""" -Default implementation of Barbican certificate processing plugins and support. -""" -from barbican.common import utils -from barbican.plugin.interface import certificate_manager as cert - -LOG = utils.getLogger(__name__) - - -MSEC_UNTIL_CHECK_STATUS = 5000 - - -class SimpleCertificatePlugin(cert.CertificatePluginBase): - """Simple/default certificate plugin.""" - - def get_default_ca_name(self): - return "Simple CA" - - def get_default_signing_cert(self): - return "XXXXXXXXXXXXXXXXX" - - def get_default_intermediates(self): - return "YYYYYYYYYYYYYYYY" - - def issue_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Create the initial order with CA - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - LOG.info('Invoking issue_certificate_request()') - return cert.ResultDTO( - cert.CertificateStatus.WAITING_FOR_CA, - retry_msec=MSEC_UNTIL_CHECK_STATUS) - - def modify_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Update the order meta-data - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - LOG.info('Invoking modify_certificate_request()') - return cert.ResultDTO(cert.CertificateStatus.WAITING_FOR_CA) - - def cancel_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Cancel the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - LOG.info('Invoking cancel_certificate_request()') - return cert.ResultDTO(cert.CertificateStatus.REQUEST_CANCELED) - - def check_certificate_status(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Check status of the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - :returns: A :class:`ResultDTO` instance containing the result - populated by the plugin implementation - :rtype: :class:`ResultDTO` - """ - LOG.info('Invoking check_certificate_status()') - return cert.ResultDTO(cert.CertificateStatus.CERTIFICATE_GENERATED) - - def supports(self, certificate_spec): - """Indicates whether the plugin supports the certificate type. - - :param certificate_spec: Contains details on the certificate to - generate the certificate order - :returns: boolean indicating if the plugin supports the certificate - type - """ - return True - - def supported_request_types(self): - """Returns the request types supported by this plugin. - - :returns: dict containing Barbican-core defined request types - supported by this plugin. - """ - return [cert.CertificateRequestType.CUSTOM_REQUEST, - cert.CertificateRequestType.SIMPLE_CMC_REQUEST, - cert.CertificateRequestType.FULL_CMC_REQUEST, - cert.CertificateRequestType.STORED_KEY_REQUEST] - - -class SimpleCertificateEventPlugin(cert.CertificateEventPluginBase): - """Simple/default certificate event plugin.""" - - def notify_certificate_is_ready( - self, project_id, order_ref, container_ref): - """Notify that a certificate has been generated and is ready to use. - - :param project_id: Project ID associated with this certificate - :param order_ref: HATEOAS reference URI to the submitted Barbican Order - :param container_ref: HATEOAS reference URI to the Container storing - the certificate - :returns: None - """ - LOG.info('Invoking notify_certificate_is_ready()') - - def notify_ca_is_unavailable( - self, project_id, order_ref, error_msg, retry_in_msec): - """Notify that the certificate authority (CA) isn't available. - - :param project_id: Project ID associated with this order - :param order_ref: HATEOAS reference URI to the submitted Barbican Order - :param error_msg: Error message if it is available - :param retry_in_msec: Delay before attempting to talk to the CA again. - If this is 0, then no attempt will be made. - :returns: None - """ - LOG.info('Invoking notify_ca_is_unavailable()') diff --git a/barbican/plugin/snakeoil_ca.py b/barbican/plugin/snakeoil_ca.py deleted file mode 100644 index f94990eb8..000000000 --- a/barbican/plugin/snakeoil_ca.py +++ /dev/null @@ -1,479 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 base64 -import datetime -import fnmatch -import os -import re -import subprocess # nosec -from tempfile import mkstemp -import uuid - -from OpenSSL import crypto -from oslo_config import cfg -from oslo_utils import uuidutils - -from barbican.common import config -from barbican.common import utils -from barbican import i18n as u -import barbican.plugin.interface.certificate_manager as cert_manager - -CONF = config.new_config() -LOG = utils.getLogger(__name__) - - -snakeoil_ca_plugin_group = cfg.OptGroup(name='snakeoil_ca_plugin', - title="Snakeoil CA Plugin Options") - -snakeoil_ca_plugin_opts = [ - cfg.StrOpt('ca_cert_path', - help=u._('Path to CA certificate file')), - cfg.StrOpt('ca_cert_key_path', - help=u._('Path to CA certificate key file')), - cfg.StrOpt('ca_cert_chain_path', - help=u._('Path to CA certificate chain file')), - cfg.StrOpt('ca_cert_pkcs7_path', - help=u._('Path to CA chain pkcs7 file')), - cfg.StrOpt('subca_cert_key_directory', - default='/etc/barbican/snakeoil-cas', - help=u._('Directory in which to store certs/keys for subcas')), -] - -CONF.register_group(snakeoil_ca_plugin_group) -CONF.register_opts(snakeoil_ca_plugin_opts, group=snakeoil_ca_plugin_group) -config.parse_args(CONF) - - -def list_opts(): - yield snakeoil_ca_plugin_group, snakeoil_ca_plugin_opts - - -def set_subject_X509Name(target, dn): - """Set target X509Name object with parsed dn. - - This is very basic and should certainly be replaced by something using - cryptography for instance, but will do for a basic test CA - """ - - # TODO(alee) Figure out why C (country) is not working - fields = dn.split(',') - for field in fields: - m = re.search(r"(\w+)\s*=\s*(.+)", field.strip()) - name = m.group(1) - value = m.group(2) - if name.lower() == 'ou': - target.OU = value - elif name.lower() == 'st': - target.ST = value - elif name.lower() == 'cn': - target.CN = value - elif name.lower() == 'l': - target.L = value - elif name.lower() == 'o': - target.O = value # noqa: E741 - return target - - -class SnakeoilCA(object): - - def __init__(self, cert_path=None, key_path=None, chain_path=None, - pkcs7_path=None, name=None, serial=1, - key_size=2048, expiry_days=10 * 365, x509_version=2, - subject_dn=None, signing_dn=None, signing_key=None, - parent_chain_path=None): - self.cert_path = cert_path - self.key_path = key_path - self.chain_path = chain_path - self.pkcs7_path = pkcs7_path - self.name = name - self.serial = serial - self.key_size = key_size - self.expiry_days = expiry_days - self.x509_version = x509_version - - self.subject_dn = subject_dn - - if signing_dn is not None: - self.signing_dn = signing_dn - else: - self.signing_dn = subject_dn # self-signed - - self.signing_key = signing_key - self.parent_chain_path = parent_chain_path - - self._cert_val = None - self._key_val = None - self._chain_val = None - self._pkcs7_val = None - - @property - def cert(self): - self.ensure_exists() - if self.cert_path: - with open(self.cert_path, 'rb') as cert_fh: - return crypto.load_certificate(crypto.FILETYPE_PEM, - cert_fh.read()) - else: - return crypto.load_certificate(crypto.FILETYPE_PEM, self._cert_val) - - @cert.setter - def cert(self, val): - if self.cert_path: - with open(self.cert_path, 'wb') as cert_fh: - cert_fh.write(crypto.dump_certificate(crypto.FILETYPE_PEM, - val)) - else: - self._cert_val = crypto.dump_certificate(crypto.FILETYPE_PEM, val) - - @property - def key(self): - self.ensure_exists() - if self.key_path: - with open(self.key_path, 'rb') as key_fh: - return crypto.load_privatekey(crypto.FILETYPE_PEM, - key_fh.read()) - else: - return crypto.load_privatekey(crypto.FILETYPE_PEM, self._key_val) - - @key.setter - def key(self, val): - if self.key_path: - with open(self.key_path, 'wb') as key_fh: - key_fh.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, val)) - else: - self._key_val = crypto.dump_privatekey(crypto.FILETYPE_PEM, val) - - @property - def chain(self): - self.ensure_exists() - if self.chain_path: - with open(self.chain_path, 'rb') as chain_fh: - return chain_fh.read() - else: - return self._chain_val - - @chain.setter - def chain(self, val): - if self.chain_path: - with open(self.chain_path, 'wb') as chain_fh: - chain_fh.write(val) - else: - self._chain_val = val - - @property - def pkcs7(self): - self.ensure_exists() - if self.pkcs7_path: - with open(self.pkcs7_path, 'rb') as pkcs7_fh: - return pkcs7_fh.read() - else: - return self._pkcs7_val - - @pkcs7.setter - def pkcs7(self, val): - if self.pkcs7_path: - with open(self.pkcs7_path, 'wb') as pkcs7_fh: - pkcs7_fh.write(val) - else: - self._pkcs7_val = val - - @property - def exists(self): - if self.cert_path is not None: - cert_exists = os.path.isfile(self.cert_path) - else: - cert_exists = self._cert_val is not None - - if self.key_path is not None: - key_exists = os.path.isfile(self.key_path) - else: - key_exists = self._key_val is not None - - if self.chain_path is not None: - chain_exists = os.path.isfile(self.chain_path) - else: - chain_exists = self._chain_val is not None - - if self.pkcs7_path is not None: - pkcs7_exists = os.path.isfile(self.pkcs7_path) - else: - pkcs7_exists = self._pkcs7_val is not None - - return (cert_exists and key_exists and - pkcs7_exists and chain_exists) - - def ensure_exists(self): - if not self.exists: - LOG.debug('Keypair not found, creating new cert/key') - self.cert, self.key, self.chain, self.pkcs7 = ( - self.create_keypair()) - - def create_keypair(self): - LOG.debug('Generating Snakeoil CA') - key = crypto.PKey() - key.generate_key(crypto.TYPE_RSA, self.key_size) - - cert = crypto.X509() - cert.set_version(self.x509_version) - cert.set_serial_number(self.serial) - subject = cert.get_subject() - set_subject_X509Name(subject, self.subject_dn) - cert.set_subject(subject) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(self.expiry_days) - cert.set_issuer(set_subject_X509Name( - cert.get_issuer(), self.signing_dn)) - cert.set_pubkey(key) - cert.add_extensions([ - crypto.X509Extension(b"basicConstraints", True, - b"CA:TRUE, pathlen:5"), - ]) - if not self.signing_key: - self.signing_key = key # self-signed - - cert.sign(self.signing_key, 'sha256') - - LOG.debug('Snakeoil CA cert/key generated') - - chain = b'' - if self.parent_chain_path: - with open(self.parent_chain_path, 'rb') as fh: - chain = fh.read() - chain += crypto.dump_certificate(crypto.FILETYPE_PEM, cert) - - pkcs7 = self._generate_pkcs7(chain) - return cert, key, chain, pkcs7 - - def _generate_pkcs7(self, chain): - fin, temp_in = mkstemp() - os.write(fin, chain) - os.close(fin) - - fout, temp_out = mkstemp() - os.close(fout) - - subprocess.call(['/usr/bin/openssl', 'crl2pkcs7', '-nocrl', # nosec - '-out', temp_out, '-certfile', temp_in], shell=False) - with open(temp_out, 'rb') as pkcs7_fh: - pkcs7 = pkcs7_fh.read() - - os.remove(temp_in) - os.remove(temp_out) - return pkcs7 - - -class CertManager(object): - - def __init__(self, ca): - self.ca = ca - - def get_new_serial(self): - return uuid.uuid4().int - - def make_certificate(self, csr, expires=2 * 365): - cert = crypto.X509() - cert.set_serial_number(self.get_new_serial()) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(expires) - cert.set_issuer(self.ca.cert.get_subject()) - cert.set_subject(csr.get_subject()) - cert.set_pubkey(csr.get_pubkey()) - cert.sign(self.ca.key, 'sha256') - return cert - - -class SnakeoilCACertificatePlugin(cert_manager.CertificatePluginBase): - """Snakeoil CA certificate plugin. - - This is used for easily generating certificates which are not useful in a - production environment. - """ - - def __init__(self, conf=CONF): - self.cas = {} - self.ca = SnakeoilCA( - cert_path=conf.snakeoil_ca_plugin.ca_cert_path, - key_path=conf.snakeoil_ca_plugin.ca_cert_key_path, - chain_path=conf.snakeoil_ca_plugin.ca_cert_chain_path, - pkcs7_path=conf.snakeoil_ca_plugin.ca_cert_pkcs7_path, - name=self.get_default_ca_name(), - subject_dn="cn=Snakeoil Certificate,o=example.com" - ) - - self.cas[self.get_default_ca_name()] = self.ca - - self.subca_directory = conf.snakeoil_ca_plugin.subca_cert_key_directory - if self.subca_directory: - if not os.path.exists(self.subca_directory): - os.makedirs(self.subca_directory) # pragma: no cover - else: - self._reload_previously_created_subcas() - - self.cert_manager = CertManager(self.ca) - - def _reload_previously_created_subcas(self): - for file in os.listdir(self.subca_directory): - if fnmatch.fnmatch(file, '*.key'): - ca_id, _ext = os.path.splitext(file) - self.cas[ca_id] = SnakeoilCA( - cert_path=os.path.join(self.subca_directory, - ca_id + ".cert"), - key_path=os.path.join(self.subca_directory, file), - chain_path=os.path.join(self.subca_directory, - ca_id + ".chain"), - pkcs7_path=os.path.join(self.subca_directory, - ca_id + ".p7b") - ) - - def get_default_ca_name(self): - return "Snakeoil CA" - - def get_default_signing_cert(self): - return crypto.dump_certificate(crypto.FILETYPE_PEM, self.ca.cert) - - def get_default_intermediates(self): - return None - - def supported_request_types(self): - return [cert_manager.CertificateRequestType.CUSTOM_REQUEST, - cert_manager.CertificateRequestType.STORED_KEY_REQUEST] - - def issue_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - if barbican_meta_dto.generated_csr is not None: - encoded_csr = barbican_meta_dto.generated_csr - else: - try: - encoded_csr = base64.b64decode(order_meta['request_data']) - except KeyError: - return cert_manager.ResultDTO( - cert_manager.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - status_message=u._("No request_data specified")) - csr = crypto.load_certificate_request(crypto.FILETYPE_PEM, encoded_csr) - - ca_id = barbican_meta_dto.plugin_ca_id - if ca_id: - ca = self.cas.get(ca_id) - if ca is None: - raise cert_manager.CertificateGeneralException( - "Invalid ca_id passed into snake oil plugin:" + ca_id) - else: - ca = self.ca - - cert_mgr = CertManager(ca) - cert = cert_mgr.make_certificate(csr) - cert_enc = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) - - return cert_manager.ResultDTO( - cert_manager.CertificateStatus.CERTIFICATE_GENERATED, - certificate=base64.b64encode(cert_enc), - intermediates=base64.b64encode(ca.pkcs7)) - - def modify_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - raise NotImplementedError - - def cancel_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - raise NotImplementedError - - def check_certificate_status(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - raise NotImplementedError - - def supports(self, certificate_spec): - request_type = certificate_spec.get( - cert_manager.REQUEST_TYPE, - cert_manager.CertificateRequestType.CUSTOM_REQUEST) - return request_type in self.supported_request_types() - - def supports_create_ca(self): - return True - - def create_ca(self, ca_create_dto): - # get the parent CA from the ca list, return error if not on list - parent_ca_id = ca_create_dto.parent_ca_id - if not parent_ca_id: - raise cert_manager.CertificateGeneralException( - "No parent id passed to snake oil plugin on create_ca") - - parent_ca = self.cas.get(parent_ca_id) - if not parent_ca: - raise cert_manager.CertificateGeneralException( - "Invalid parent id passed to snake oil plugin:" + parent_ca_id) - - # create a new ca, passing in key and issuer from the parent - new_ca_id = uuidutils.generate_uuid() - new_cert_path = os.path.join(self.subca_directory, new_ca_id + ".cert") - new_key_path = os.path.join(self.subca_directory, new_ca_id + ".key") - new_chain_path = os.path.join(self.subca_directory, - new_ca_id + ".chain") - new_pkcs7_path = os.path.join(self.subca_directory, - new_ca_id + ".p7b") - parent_chain_path = parent_ca.chain_path - - new_ca = SnakeoilCA(cert_path=new_cert_path, - key_path=new_key_path, - chain_path=new_chain_path, - pkcs7_path=new_pkcs7_path, - name=ca_create_dto.name, - subject_dn=ca_create_dto.subject_dn, - signing_dn=parent_ca.subject_dn, - signing_key=parent_ca.key, - parent_chain_path=parent_chain_path) - - self.cas[new_ca_id] = new_ca - - expiration = (datetime.datetime.utcnow() + datetime.timedelta( - days=cert_manager.CA_INFO_DEFAULT_EXPIRATION_DAYS)) - - return { - cert_manager.INFO_NAME: new_ca.name, - cert_manager.INFO_CA_SIGNING_CERT: crypto.dump_certificate( - crypto.FILETYPE_PEM, new_ca.cert), - cert_manager.INFO_EXPIRATION: expiration.isoformat(), - cert_manager.INFO_INTERMEDIATES: new_ca.pkcs7, - cert_manager.PLUGIN_CA_ID: new_ca_id - } - - def get_ca_info(self): - expiration = (datetime.datetime.utcnow() + datetime.timedelta( - days=cert_manager.CA_INFO_DEFAULT_EXPIRATION_DAYS)) - - ret = {} - for ca_id, ca in self.cas.items(): - ca_info = { - cert_manager.INFO_NAME: ca.name, - cert_manager.INFO_CA_SIGNING_CERT: crypto.dump_certificate( - crypto.FILETYPE_PEM, ca.cert), - cert_manager.INFO_INTERMEDIATES: ca.pkcs7, - cert_manager.INFO_EXPIRATION: expiration.isoformat() - } - ret[ca_id] = ca_info - - return ret - - def delete_ca(self, ca_id): - self.cas.pop(ca_id) - - ca_files = [os.path.join(self.subca_directory, ca_id + ".cert"), - os.path.join(self.subca_directory, ca_id + ".key"), - os.path.join(self.subca_directory, ca_id + ".chain"), - os.path.join(self.subca_directory, ca_id + ".p7b")] - - for ca_file in ca_files: - if os.path.exists(ca_file): - os.remove(ca_file) diff --git a/barbican/plugin/symantec.py b/barbican/plugin/symantec.py deleted file mode 100644 index cbac58513..000000000 --- a/barbican/plugin/symantec.py +++ /dev/null @@ -1,306 +0,0 @@ -# Copyright (c) 2013-2014 Rackspace, Inc. -# -# 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. - -""" -Barbican certificate processing plugins and support. -""" -from oslo_config import cfg -from requests import exceptions as request_exceptions -from symantecssl.core import Symantec -from symantecssl import exceptions as symantec_exceptions - -from barbican.common import config -from barbican.common import utils -from barbican import i18n as u -from barbican.plugin.interface import certificate_manager as cert - -CONF = config.new_config() -LOG = utils.getLogger(__name__) - -symantec_plugin_group = cfg.OptGroup(name='symantec_plugin', - title='Symantec Plugin Options') - -symantec_plugin_opts = [ - cfg.StrOpt('username', - deprecated_for_removal=True, - deprecated_reason=('Symantec certificate plugin has been ' - 'deprecated'), - help=u._('Symantec username for authentication')), - cfg.StrOpt('password', - deprecated_for_removal=True, - deprecated_reason=('Symantec certificate plugin has been ' - 'deprecated'), - help=u._('Symantec password for authentication'), - secret=True), - cfg.StrOpt('url', - deprecated_for_removal=True, - deprecated_reason=('Symantec certificate plugin has been ' - 'deprecated'), - help=u._('Domain of Symantec API')) -] - -CONF.register_group(symantec_plugin_group) -CONF.register_opts(symantec_plugin_opts, group=symantec_plugin_group) -config.parse_args(CONF) - - -class SymantecCertificatePlugin(cert.CertificatePluginBase): - """Symantec certificate plugin.""" - - def __init__(self, conf=CONF): - self.username = conf.symantec_plugin.username - self.password = conf.symantec_plugin.password - self.url = conf.symantec_plugin.url - - if self.username is None: - raise ValueError(u._("username is required")) - - if self.password is None: - raise ValueError(u._("password is required")) - - if self.url is None: - raise ValueError(u._("url is required")) - - LOG.warning('Symantec certificate plugin has been deprecated and ' - 'will be removed in a future release.') - - def get_default_ca_name(self): - return "Symantec CA" - - def get_default_signing_cert(self): - # TODO(chellygel) Add code to get the signing cert - return None - - def get_default_intermediates(self): - # TODO(chellygel) Add code to get the cert chain - return None - - def issue_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Create the initial order with CA - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - :returns: ResultDTO - """ - successful, error_msg, can_retry = _ca_create_order(order_meta, - plugin_meta) - - status = cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST - message = None - - if successful: - status = cert.CertificateStatus.WAITING_FOR_CA - elif can_retry: - status = cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN - message = error_msg - - return cert.ResultDTO(status=status, status_message=message) - - def modify_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Update the order meta-data - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - """ - raise NotImplementedError # pragma: no cover - - def cancel_certificate_request(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Cancel the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - """ - raise NotImplementedError # pragma: no cover - - def check_certificate_status(self, order_id, order_meta, plugin_meta, - barbican_meta_dto): - """Check status of the order - - :param order_id: ID associated with the order - :param order_meta: Dict of meta-data associated with the order. - :param plugin_meta: Plugin meta-data previously set by calls to - this plugin. Plugins may also update/add - information here which Barbican will persist - on their behalf. - :param barbican_meta_dto: additional data needed to process order. - """ - raise NotImplementedError # pragma: no cover - - def supports(self, certificate_spec): - """Indicates if the plugin supports the certificate type. - - :param certificate_spec: Contains details on the certificate to - generate the certificate order - :returns: boolean indicating if the plugin supports the certificate - type - """ - # TODO(chellygel): Research what certificate types are supported by - # symantec. Returning True for testing purposes - return True - - -def _ca_create_order(self, order_meta, plugin_meta): - """Creates an order with the Symantec CA. - - The PartnerOrderId and GeoTrustOrderId are returned and stored in - plugin_meta. PartnerCode and ProductCode are also stored in plugin_meta - for future use. - - All required order parameters must be stored as a dict in - order_meta. - Required fields are: - PartnerCode, ProductCode, PartnerOrderId, OrganizationName, - AddressLine1, City, Region, PostalCode, Country, OrganizationPhone - ValidityPeriod, ServerCount, WebServerType, AdminContactFirstName, - AdminContactLastName, AdminContactPhone, AdminContactEmail, - AdminContactTitle, AdminContactAddressLine1, AdminContactCity, - AdminContactRegion, AdminContactPostalCode, AdminContactCountry, - BillingContact*, TechContact*, and CSR. - - *The Billing and Tech contact information follows the same convention - as the AdminContact fields. - - Optional Parameters: TechSameAsAdmin, BillSameAsAdmin, more options can be - found in Symantec's API docs. Contact Symantec for the API document. - - :returns: tuple with success, error message, and can retry - """ - - api = Symantec(self.username, self.password, self.url) - - try: - order_data = api.order(**order_meta) - - # GeotrustOrderId is used to handle emails from Symantec. - # PartnerCode and ProductCode are being stored in plugin_meta for - # convenience when calling _ca_get_order_status, _ca_modify_order, etc. - plugin_meta["GeotrustOrderID"] = order_data["GeotrustOrderID"] - plugin_meta["PartnerOrderID"] = order_data["PartnerOrderID"] - plugin_meta["PartnerCode"] = order_meta["OrderDetails"]["PartnerCode"] - plugin_meta["ProductCode"] = order_meta["OrderDetails"]["ProductCode"] - return True, None, False - except symantec_exceptions.SymantecError as e: - return False, e, False - except request_exceptions.RequestException as e: - return False, e, True - - -def _ca_get_order_status(self, plugin_meta): - """Sends a request to the Symantec CA for details on an order. - - Parameters needed for GetOrderByPartnerOrderID: - plugin_meta parameters: PartnerOrderId, PartnerCode - - If the order is complete, the Certificate is returned as a string. - returns: tuple with success, error message, can retry, - and the certificate (if available). - """ - api = Symantec(self.username, self.password, self.url) - - order_details = { - "PartnerOrderID": plugin_meta["PartnerOrderID"], - "PartnerCode": plugin_meta["PartnerCode"], - "ReturnCertificateInfo": "TRUE", - "ReturnFulfillment": "TRUE", - "ReturnCaCerts": "TRUE", - } - - try: - order_data = api.get_order_by_partner_order_id(**order_details) - if order_data["OrderInfo"]["OrderState"] == "COMPLETED": - ca = order_data["Fulfillment"]["CACertificates"]["CACertificate"] - return True, None, False, ca["CACert"] - return True, None, False, None - except symantec_exceptions.SymantecError as e: - return False, e, False, None - except request_exceptions.RequestException as e: - return False, e, True, None - - -def _ca_modify_order(self, order_meta, plugin_meta): - """Sends a request to the Symantec CA to modify an order. - - Parameters needed for modifyOrder: - PartnerOrderID - Needed to specify order - PartnerCode - Needed to specify order - ProductCode - Needed to specify order - - Also need a dict, order_meta with the parameters/values to modify. - - returns: tuple with success, error message, and can retry. - """ - api = Symantec(self.username, self.password, self.url) - - order_details = { - "PartnerOrderID": plugin_meta["PartnerOrderID"], - "PartnerCode": plugin_meta["PartnerCode"], - "ProductCode": plugin_meta["ProductCode"], - } - - order_details.update(order_meta) - - try: - api.validate_order_parameters(**order_details) - return True, None, False - except symantec_exceptions.SymantecError as e: - return False, e, False - except request_exceptions.RequestException as e: - return False, e, True - - -def _ca_cancel_order(self, plugin_meta): - """Sends a request to the Symantec CA to cancel an order. - - Parameters needed for modifyOrder: - PartnerOrderID - Needed to specify order - PartnerCode - Needed to specify order - ProductCode - Needed to specify order - - returns: tuple with success, error message, and can retry. - """ - api = Symantec(self.username, self.password, self.url) - - order_details = { - "PartnerOrderID": plugin_meta["PartnerOrderID"], - "PartnerCode": plugin_meta["PartnerCode"], - "ProductCode": plugin_meta["ProductCode"], - "ModifyOrderOperation": "CANCEL", - } - - try: - api.modify_order(**order_details) - return True, None, False - except symantec_exceptions.SymantecError as e: - return False, e, False - except request_exceptions.RequestException as e: - return False, e, True diff --git a/barbican/queue/client.py b/barbican/queue/client.py index 34c5101ae..49feec58c 100644 --- a/barbican/queue/client.py +++ b/barbican/queue/client.py @@ -46,13 +46,6 @@ class TaskClient(object): project_id=project_id, request_id=request_id) - def check_certificate_status(self, order_id, project_id, request_id): - """Check the status of a certificate order.""" - self._cast('check_certificate_status', - order_id=order_id, - project_id=project_id, - request_id=request_id) - def _cast(self, name, **kwargs): """Asynchronous call handler. Barbican probably only needs casts. diff --git a/barbican/queue/server.py b/barbican/queue/server.py index 1aab5ff0f..88e0f63b9 100644 --- a/barbican/queue/server.py +++ b/barbican/queue/server.py @@ -43,9 +43,7 @@ LOG = utils.getLogger(__name__) # Maps the common/shared RetryTasks (returned from lower-level business logic # and plugin processing) to top-level RPC tasks in the Tasks class below. -MAP_RETRY_TASKS = { - common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK: 'check_certificate_status' -} +MAP_RETRY_TASKS = {} def find_function_name(func, if_no_name=None): @@ -211,20 +209,6 @@ class Tasks(object): return resources.BeginTypeOrder().process_and_suppress_exceptions( order_id, project_id) - @monitored - @transactional - @retryable_order - def check_certificate_status(self, context, order_id, - project_id, request_id): - """Check the status of a certificate order.""" - message = "Processing check certificate status on order: " \ - "order ID is '%(order)s' and request ID is '%(request)s'" - - LOG.info(message, {'order': order_id, 'request': request_id}) - check_cert_order = resources.CheckCertificateStatusOrder() - return check_cert_order.process_and_suppress_exceptions( - order_id, project_id) - class TaskServer(Tasks, service.Service): """Server to process asynchronous tasking from Barbican API nodes. diff --git a/barbican/tasks/certificate_resources.py b/barbican/tasks/certificate_resources.py deleted file mode 100644 index 8143afb0d..000000000 --- a/barbican/tasks/certificate_resources.py +++ /dev/null @@ -1,594 +0,0 @@ -# Copyright (c) 2013-2014 Rackspace, Inc. -# -# 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 ldap3.utils.dn import parse_dn -from OpenSSL import crypto - -from barbican.common import exception as excep -from barbican.common import hrefs -from barbican.common import resources as res -import barbican.common.utils as utils -from barbican.model import models -from barbican.model import repositories as repos -from barbican.plugin.interface import certificate_manager as cert -from barbican.plugin import resources as plugin -from barbican.tasks import common - -LOG = utils.getLogger(__name__) - -# Order sub-status definitions -ORDER_STATUS_REQUEST_PENDING = models.OrderStatus( - "cert_request_pending", - "Request has been submitted to the CA. " - "Waiting for certificate to be generated" -) - -ORDER_STATUS_CERT_GENERATED = models.OrderStatus( - "cert_generated", - "Certificate has been generated" -) - -ORDER_STATUS_DATA_INVALID = models.OrderStatus( - "cert_data_invalid", - "CA rejected request data as invalid" -) - -ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE = models.OrderStatus( - "cert_ca_unavail_for_issue", - "Unable to submit certificate request. CA unavailable" -) - -ORDER_STATUS_INVALID_OPERATION = models.OrderStatus( - "cert_invalid_operation", - "CA returned invalid operation" -) - -ORDER_STATUS_INTERNAL_ERROR = models.OrderStatus( - "cert_internal_error", - "Internal error during certificate operations" -) - -ORDER_STATUS_CA_UNAVAIL_FOR_CHECK = models.OrderStatus( - "cert_ca_unavail_for_status_check", - "Unable to get certificate request status. CA unavailable." -) - - -def refresh_certificate_resources(): - # Before CA operations can be performed, the CA table must be populated - cert.CertificatePluginManager().refresh_ca_table() - - -def issue_certificate_request(order_model, project_model, result_follow_on): - """Create the initial order with CA. - - Note that this method may be called more than once if retries are - required. Barbican metadata is used to store intermediate information, - including selected plugins by name, to support such retries. - - :param: order_model - order associated with this cert request - :param: project_model - project associated with this request - :param: result_follow_on - A :class:`FollowOnProcessingStatusDTO` instance - instantiated by the client that this function may optionally update - with information on how to process this task into the future. - :returns: container_model - container with the relevant cert if - the request has been completed. None otherwise - """ - plugin_meta = _get_plugin_meta(order_model) - barbican_meta = _get_barbican_meta(order_model) - - # TODO(john-wood-w) We need to de-conflict barbican_meta (stored with order - # and not shown to plugins) with barbican_meta_dto (shared with plugins). - # As a minimum we should change the name of the DTO to something like - # 'extended_meta_dto' or some such. - barbican_meta_for_plugins_dto = cert.BarbicanMetaDTO() - - # refresh the CA table. This is mostly a no-op unless the entries - # for a plugin are expired. - cert.CertificatePluginManager().refresh_ca_table() - - cert_plugin = _get_cert_plugin(barbican_meta, - barbican_meta_for_plugins_dto, - order_model, project_model) - barbican_meta['plugin_name'] = utils.generate_fullname_for(cert_plugin) - - # Generate CSR if needed. - request_type = order_model.meta.get(cert.REQUEST_TYPE) - if request_type == cert.CertificateRequestType.STORED_KEY_REQUEST: - csr = barbican_meta.get('generated_csr') - if csr is None: - # TODO(alee) Fix this to be a non-project specific call once - # the ACL patches go in. - csr = _generate_csr_from_private_key(order_model, project_model) - barbican_meta['generated_csr'] = csr - barbican_meta_for_plugins_dto.generated_csr = csr - - result = cert_plugin.issue_certificate_request( - order_model.id, order_model.meta, - plugin_meta, barbican_meta_for_plugins_dto) - - # Save plugin and barbican metadata for this order. - _save_plugin_metadata(order_model, plugin_meta) - _save_barbican_metadata(order_model, barbican_meta) - - # Handle result - return _handle_task_result( - result, result_follow_on, order_model, project_model, request_type, - unavailable_status=ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE) - - -def _get_cert_plugin(barbican_meta, barbican_meta_for_plugins_dto, - order_model, project_model): - cert_plugin_name = barbican_meta.get('plugin_name') - if cert_plugin_name: - return cert.CertificatePluginManager().get_plugin_by_name( - cert_plugin_name) - ca_id = _get_ca_id(order_model.meta, project_model.id) - if ca_id: - ca = repos.get_ca_repository().get(ca_id) - barbican_meta_for_plugins_dto.plugin_ca_id = ca.plugin_ca_id - return cert.CertificatePluginManager().get_plugin_by_name( - ca.plugin_name) - else: - return cert.CertificatePluginManager().get_plugin(order_model.meta) - - -def check_certificate_request(order_model, project_model, result_follow_on): - """Check the status of a certificate request with the CA. - - Note that this method may be called more than once if retries are - required. Barbican metadata is used to store intermediate information, - including selected plugins by name, to support such retries. - - :param: order_model - order associated with this cert request - :param: project_model - project associated with this request - :param: result_follow_on - A :class:`FollowOnProcessingStatusDTO` instance - instantiated by the client that this function may optionally update - with information on how to process this task into the future. - :returns: container_model - container with the relevant cert if the - request has been completed. None otherwise. - """ - plugin_meta = _get_plugin_meta(order_model) - barbican_meta = _get_barbican_meta(order_model) - - # TODO(john-wood-w) See note above about DTO's name. - barbican_meta_for_plugins_dto = cert.BarbicanMetaDTO() - - cert_plugin = cert.CertificatePluginManager().get_plugin_by_name( - barbican_meta.get('plugin_name')) - - result = cert_plugin.check_certificate_status( - order_model.id, order_model.meta, - plugin_meta, barbican_meta_for_plugins_dto) - - # Save plugin order plugin state - _save_plugin_metadata(order_model, plugin_meta) - - request_type = order_model.meta.get(cert.REQUEST_TYPE) - return _handle_task_result( - result, result_follow_on, order_model, project_model, request_type, - unavailable_status=ORDER_STATUS_CA_UNAVAIL_FOR_CHECK) - - -def create_subordinate_ca(project_model, name, description, subject_dn, - parent_ca_ref, creator_id): - """Create a subordinate CA - - :param name - name of the subordinate CA - :param: description - description of the subordinate CA - :param: subject_dn - subject DN of the subordinate CA - :param: parent_ca_ref - Barbican URL reference to the parent CA - :param: creator_id - id for creator of the subordinate CA - :return: :class models.CertificateAuthority model object for new sub CA - """ - # check that the parent ref exists and is accessible - parent_ca_id = hrefs.get_ca_id_from_ref(parent_ca_ref) - ca_repo = repos.get_ca_repository() - parent_ca = ca_repo.get(entity_id=parent_ca_id, suppress_exception=True) - if not parent_ca: - raise excep.InvalidParentCA(parent_ca_ref=parent_ca_ref) - - # Parent CA must be a base CA or a subCA owned by this project - if (parent_ca.project_id is not None and - parent_ca.project_id != project_model.id): - raise excep.UnauthorizedSubCA() - - # get the parent plugin, raises CertPluginNotFound if missing - cert_plugin = cert.CertificatePluginManager().get_plugin_by_name( - parent_ca.plugin_name) - - # confirm that the plugin supports creating subordinate CAs - if not cert_plugin.supports_create_ca(): - raise excep.SubCAsNotSupported() - - # make call to create the subordinate ca - create_ca_dto = cert.CACreateDTO( - name=name, - description=description, - subject_dn=subject_dn, - parent_ca_id=parent_ca.plugin_ca_id) - - new_ca_dict = cert_plugin.create_ca(create_ca_dto) - if not new_ca_dict: - raise excep.SubCANotCreated(name=name) - - # create and store the subordinate CA as a new certificate authority object - new_ca_dict['plugin_name'] = parent_ca.plugin_name - new_ca_dict['creator_id'] = creator_id - new_ca_dict['project_id'] = project_model.id - new_ca = models.CertificateAuthority(new_ca_dict) - ca_repo.create_from(new_ca) - - return new_ca - - -def delete_subordinate_ca(external_project_id, ca): - """Deletes a subordinate CA and any related artifacts - - :param external_project_id: external project ID - :param ca: class:`models.CertificateAuthority` to be deleted - :return: None - """ - # TODO(alee) See if the checks below can be moved to the RBAC code - - # Check that this CA is a subCA - if ca.project_id is None: - raise excep.CannotDeleteBaseCA() - - # Check that the user's project owns this subCA - project = res.get_or_create_project(external_project_id) - if ca.project_id != project.id: - raise excep.UnauthorizedSubCA() - - project_ca_repo = repos.get_project_ca_repository() - (project_cas, _, _, _) = project_ca_repo.get_by_create_date( - project_id=project.id, ca_id=ca.id, - suppress_exception=True) - - preferred_ca_repo = repos.get_preferred_ca_repository() - (preferred_cas, _, _, _) = preferred_ca_repo.get_by_create_date( - project_id=project.id, ca_id=ca.id, suppress_exception=True) - - # Can not delete a project preferred CA, if other project CAs exist. One - # of those needs to be designated as the preferred CA first. - if project_cas and preferred_cas and not is_last_project_ca(project.id): - raise excep.CannotDeletePreferredCA() - - # Remove the CA as preferred - if preferred_cas: - preferred_ca_repo.delete_entity_by_id(preferred_cas[0].id, - external_project_id) - # Remove the CA from project list - if project_cas: - project_ca_repo.delete_entity_by_id(project_cas[0].id, - external_project_id) - - # Delete the CA entry from plugin - cert_plugin = cert.CertificatePluginManager().get_plugin_by_name( - ca.plugin_name) - cert_plugin.delete_ca(ca.plugin_ca_id) - - # Finally, delete the CA entity from the CA repository - ca_repo = repos.get_ca_repository() - ca_repo.delete_entity_by_id( - entity_id=ca.id, - external_project_id=external_project_id) - - -def is_last_project_ca(project_id): - """Returns True iff project has exactly one project CA - - :param project_id: internal project ID - :return: Boolean - """ - project_ca_repo = repos.get_project_ca_repository() - _, _, _, total = project_ca_repo.get_by_create_date( - project_id=project_id, - suppress_exception=True - ) - return total == 1 - - -def _handle_task_result(result, result_follow_on, order_model, - project_model, request_type, unavailable_status): - if cert.CertificateStatus.WAITING_FOR_CA == result.status: - _update_result_follow_on( - result_follow_on, - order_status=ORDER_STATUS_REQUEST_PENDING, - retry_task=common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK, - retry_msec=result.retry_msec) - elif cert.CertificateStatus.CERTIFICATE_GENERATED == result.status: - _update_result_follow_on( - result_follow_on, - order_status=ORDER_STATUS_CERT_GENERATED) - container_model = _save_secrets(result, project_model, request_type, - order_model) - return container_model - elif cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN == result.status: - raise cert.CertificateStatusClientDataIssue(result.status_message) - elif cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST == result.status: - _update_result_follow_on( - result_follow_on, - order_status=unavailable_status, - retry_task=common.RetryTasks.INVOKE_SAME_TASK, - retry_msec=cert.ERROR_RETRY_MSEC) - _notify_ca_unavailable(order_model, result) - elif cert.CertificateStatus.INVALID_OPERATION == result.status: - raise cert.CertificateStatusInvalidOperation(result.status_message) - else: - raise cert.CertificateStatusNotSupported(result.status) - - return None - - -def _add_private_key_to_generated_cert_container(container_id, order_model, - project_model): - keypair_container_id, keypair_container = _get_container_from_order_meta( - order_model, project_model) - private_key_id = None - - for cs in keypair_container.container_secrets: - if cs.name == 'private_key': - private_key_id = cs.secret_id - - new_consec_assoc = models.ContainerSecret() - new_consec_assoc.name = 'private_key' - new_consec_assoc.container_id = container_id - new_consec_assoc.secret_id = private_key_id - container_secret_repo = repos.get_container_secret_repository() - container_secret_repo.create_from(new_consec_assoc) - - -def modify_certificate_request(order_model, updated_meta): - """Update the order with CA.""" - # TODO(chellygel): Add the modify certificate request logic. - LOG.debug('in modify_certificate_request') - raise NotImplementedError # pragma: no cover - - -def get_global_preferred_ca(): - project = res.get_or_create_global_preferred_project() - preferred_ca_repository = repos.get_preferred_ca_repository() - cas = preferred_ca_repository.get_project_entities(project.id) - if not cas: - return None - else: - return cas[0] - - -def get_project_preferred_ca_id(project_id): - """Compute the preferred CA ID for a project - - First priority: a preferred CA is defined for the project - Second priority: a preferred CA is defined globally - Else: None - """ - preferred_ca_repository = repos.get_preferred_ca_repository() - cas, offset, limit, total = preferred_ca_repository.get_by_create_date( - project_id=project_id, suppress_exception=True) - if total > 0: - return cas[0].ca_id - global_ca = get_global_preferred_ca() - if global_ca: - return global_ca.ca_id - - -def _get_ca_id(order_meta, project_id): - ca_id = order_meta.get(cert.CA_ID) - if ca_id: - return ca_id - - return get_project_preferred_ca_id(project_id) - - -def _update_result_follow_on( - result_follow_on, - order_status=None, - retry_task=common.RetryTasks.NO_ACTION_REQUIRED, - retry_msec=common.RETRY_MSEC_DEFAULT): - if order_status: - result_follow_on.status = order_status.id - result_follow_on.status_message = order_status.message - result_follow_on.retry_task = retry_task - if retry_msec and retry_msec >= 0: - result_follow_on.retry_msec = retry_msec - - -def _get_plugin_meta(order_model): - if order_model: - order_plugin_meta_repo = repos.get_order_plugin_meta_repository() - return order_plugin_meta_repo.get_metadata_for_order(order_model.id) - else: - return {} - - -def _get_barbican_meta(order_model): - if order_model: - order_barbican_meta_repo = repos.get_order_barbican_meta_repository() - return order_barbican_meta_repo.get_metadata_for_order(order_model.id) - else: - return {} - - -def _generate_csr_from_private_key(order_model, project_model): - """Generate a CSR from the private key. - - :param: order_model - order for the request - :param: project_model - project for this request - :return: CSR (certificate signing request) in PEM format - :raise: :class:`StoredKeyPrivateKeyNotFound` if private key not found - :class:`StoredKeyContainerNotFound` if container not found - """ - container_id, container = _get_container_from_order_meta(order_model, - project_model) - - if not container: - raise excep.StoredKeyContainerNotFound(container_id) - - passphrase = None - private_key = None - - for cs in container.container_secrets: - secret_repo = repos.get_secret_repository() - if cs.name == 'private_key': - private_key_model = secret_repo.get( - cs.secret_id, - project_model.external_id) - private_key = plugin.get_secret( - 'application/pkcs8', - private_key_model, - project_model) - elif cs.name == 'private_key_passphrase': - passphrase_model = secret_repo.get( - cs.secret_id, - project_model.external_id) - passphrase = plugin.get_secret( - 'text/plain;charset=utf-8', - passphrase_model, - project_model) - passphrase = str(passphrase) - - if not private_key: - raise excep.StoredKeyPrivateKeyNotFound(container.id) - - if passphrase is None: - pkey = crypto.load_privatekey( - crypto.FILETYPE_PEM, - private_key - ) - else: - pkey = crypto.load_privatekey( - crypto.FILETYPE_PEM, - private_key, - passphrase.encode('utf-8') - ) - - subject_name = order_model.meta.get('subject_dn') - subject_name_dns = parse_dn(subject_name) - extensions = order_model.meta.get('extensions', None) - - req = crypto.X509Req() - subj = req.get_subject() - - # Note: must iterate over the DNs in reverse order, or the resulting - # subject name will be reversed. - for ava in reversed(subject_name_dns): - key, val, extra = ava - setattr(subj, key.upper(), val) - req.set_pubkey(pkey) - if extensions: - # TODO(alee-3) We need code here to parse the encoded extensions and - # convert them into X509Extension objects. This code will also be - # used in the validation code. Commenting out for now till we figure - # out how to do this. - # req.add_extensions(extensions) - pass - req.sign(pkey, 'sha256') - - csr = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - return csr - - -def _get_container_from_order_meta(order_model, project_model): - container_ref = order_model.meta.get('container_ref') - - # extract container_id as the last part of the URL - container_id = hrefs.get_container_id_from_ref(container_ref) - - container_repo = repos.get_container_repository() - container = container_repo.get(container_id, - project_model.external_id, - suppress_exception=True) - return container_id, container - - -def _notify_ca_unavailable(order_model, result): - """Notify observer(s) that the CA was unavailable at this time.""" - cert.get_event_plugin_manager().notify_ca_is_unavailable( - order_model.project_id, - hrefs.convert_order_to_href(order_model.id), - result.status_message, - result.retry_msec) - - -def _save_plugin_metadata(order_model, plugin_meta): - """Add plugin metadata to an order.""" - - if not isinstance(plugin_meta, dict): - plugin_meta = {} - - order_plugin_meta_repo = repos.get_order_plugin_meta_repository() - order_plugin_meta_repo.save(plugin_meta, order_model) - - -def _save_barbican_metadata(order_model, barbican_meta): - """Add barbican metadata to an order.""" - - if not isinstance(barbican_meta, dict): - barbican_meta = {} - - order_barbican_meta_repo = repos.get_order_barbican_meta_repository() - order_barbican_meta_repo.save(barbican_meta, order_model) - - -def _save_secrets(result, project_model, request_type, order_model): - cert_secret_model, transport_key_model = plugin.store_secret( - unencrypted_raw=result.certificate, - content_type_raw='application/octet-stream', - content_encoding='base64', - secret_model=models.Secret(), - project_model=project_model) - - # save the certificate chain as a secret. - if result.intermediates: - intermediates_secret_model, transport_key_model = plugin.store_secret( - unencrypted_raw=result.intermediates, - content_type_raw='application/octet-stream', - content_encoding='base64', - secret_model=models.Secret(), - project_model=project_model - ) - else: - intermediates_secret_model = None - - container_model = models.Container() - container_model.type = "certificate" - container_model.status = models.States.ACTIVE - container_model.project_id = project_model.id - container_repo = repos.get_container_repository() - container_repo.create_from(container_model) - - # create container_secret for certificate - new_consec_assoc = models.ContainerSecret() - new_consec_assoc.name = 'certificate' - new_consec_assoc.container_id = container_model.id - new_consec_assoc.secret_id = cert_secret_model.id - container_secret_repo = repos.get_container_secret_repository() - container_secret_repo.create_from(new_consec_assoc) - - if intermediates_secret_model: - # create container_secret for intermediate certs - new_consec_assoc = models.ContainerSecret() - new_consec_assoc.name = 'intermediates' - new_consec_assoc.container_id = container_model.id - new_consec_assoc.secret_id = intermediates_secret_model.id - container_secret_repo.create_from(new_consec_assoc) - - if request_type == cert.CertificateRequestType.STORED_KEY_REQUEST: - _add_private_key_to_generated_cert_container(container_model.id, - order_model, - project_model) - - return container_model diff --git a/barbican/tasks/common.py b/barbican/tasks/common.py index 4c60fcc3f..15d4a3a88 100644 --- a/barbican/tasks/common.py +++ b/barbican/tasks/common.py @@ -39,16 +39,10 @@ class RetryTasks(object): NO_ACTION_REQUIRED - To retry/scheduling actions are required - - The following task/context-specific actions are available: - - INVOKE_CERT_STATUS_CHECK_TASK - Check certificate status later - """ INVOKE_SAME_TASK = "Invoke Same Task Again Later" NO_ACTION_REQUIRED = "No Retry/Schedule Actions Are Needed" - INVOKE_CERT_STATUS_CHECK_TASK = "Check Certificate Status Later" class FollowOnProcessingStatusDTO(object): diff --git a/barbican/tasks/resources.py b/barbican/tasks/resources.py index 9c9e53b99..73e271213 100644 --- a/barbican/tasks/resources.py +++ b/barbican/tasks/resources.py @@ -24,7 +24,6 @@ from barbican import i18n as u from barbican.model import models from barbican.model import repositories as rep from barbican.plugin import resources as plugin -from barbican.tasks import certificate_resources as cert from barbican.tasks import common @@ -288,13 +287,6 @@ class BeginTypeOrder(BaseTask): project) order.container_id = new_container.id LOG.debug("...done creating asymmetric order's secret.") - elif order_type == models.OrderType.CERTIFICATE: - # Request a certificate - new_container = cert.issue_certificate_request( - order, project, result_follow_on) - if new_container: - order.container_id = new_container.id - LOG.debug("...done requesting a certificate.") else: raise NotImplementedError( u._('Order type "{order_type}" not implemented.').format( @@ -310,107 +302,3 @@ class BeginTypeOrder(BaseTask): def handle_success(self, order, result, *args, **kwargs): self.helper.handle_success( order, result, *args, **kwargs) - - -class UpdateOrder(BaseTask): - """Handles updating an order.""" - def get_name(self): - return u._('Update Order') - - def __init__(self): - super(UpdateOrder, self).__init__() - LOG.debug('Creating UpdateOrder task processor') - self.helper = _OrderTaskHelper() - - def retrieve_entity(self, *args, **kwargs): - return self.helper.retrieve_entity(*args, **kwargs) - - def handle_processing( - self, order, order_id, external_project_id, updated_meta): - self.handle_order(order, updated_meta) - - def handle_order(self, order, updated_meta): - """Handle Order Update - - :param order: Order to update. - """ - - order_info = order.to_dict_fields() - order_type = order_info.get('type') - - if order_type == models.OrderType.CERTIFICATE: - # Update a certificate request - cert.modify_certificate_request(order, updated_meta) - LOG.debug("...done updating a certificate order.") - else: - raise NotImplementedError( - u._('Order type "{order_type}" not implemented.').format( - order_type=order_type)) - - LOG.debug("...done updating order.") - - def handle_error(self, order, status, message, exception, - *args, **kwargs): - self.helper.handle_error( - order, status, message, exception, *args, **kwargs) - - def handle_success(self, order, result, *args, **kwargs): - self.helper.handle_success( - order, result, *args, **kwargs) - - -class CheckCertificateStatusOrder(BaseTask): - """Handles checking the status of a certificate order.""" - - def get_name(self): - return u._('Check Certificate Order Status') - - def __init__(self): - LOG.debug('Creating CheckCertificateStatusOrder task processor') - self.project_repo = rep.get_project_repository() - self.helper = _OrderTaskHelper() - - def retrieve_entity(self, *args, **kwargs): - return self.helper.retrieve_entity(*args, **kwargs) - - def handle_processing(self, order, *args, **kwargs): - return self.handle_order(order) - - def handle_order(self, order): - """Handle checking the status of a certificate order. - - :param order: Order to process. - :return: None if no follow on processing is needed for this task, - otherwise a :class:`FollowOnProcessingStatusDTO` instance - with information on how to process this task into the future. - """ - result_follow_on = common.FollowOnProcessingStatusDTO() - - order_info = order.to_dict_fields() - order_type = order_info.get('type') - - # Retrieve the project. - project = self.project_repo.get(order.project_id) - - if order_type != models.OrderType.CERTIFICATE: - raise NotImplementedError( - u._('Order type "{order_type}" not supported.').format( - order_type=order_type)) - - # Request a certificate - new_container = cert.check_certificate_request( - order, project, result_follow_on) - if new_container: - order.container_id = new_container.id - LOG.debug("...done checking status of a certificate order.") - - return result_follow_on - - def handle_error(self, order, status, message, exception, - *args, **kwargs): - self.helper.handle_error( - order, status, message, exception, *args, **kwargs) - - def handle_success(self, order, result, *args, **kwargs): - self.helper.handle_success( - order, result, *args, **kwargs) diff --git a/barbican/tests/plugin/interface/test_certificate_manager.py b/barbican/tests/plugin/interface/test_certificate_manager.py deleted file mode 100644 index 8592def18..000000000 --- a/barbican/tests/plugin/interface/test_certificate_manager.py +++ /dev/null @@ -1,316 +0,0 @@ -# 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 datetime -from unittest import mock - -import testtools - -from barbican.common import utils as common_utils -from barbican.model import models -from barbican.plugin.interface import certificate_manager as cm -from barbican.tests import database_utils -from barbican.tests import utils - - -class WhenTestingCertificateEventPluginManager(testtools.TestCase): - - def setUp(self): - super(WhenTestingCertificateEventPluginManager, self).setUp() - - self.project_id = '1234' - self.order_ref = 'http://www.mycerts.com/v1/orders/123456' - self.container_ref = 'http://www.mycerts.com/v1/containers/654321' - self.error_msg = 'Something is broken' - self.retry_in_msec = 5432 - - self.plugin_returned = mock.MagicMock() - self.plugin_name = common_utils.generate_fullname_for( - self.plugin_returned) - self.plugin_loaded = mock.MagicMock(obj=self.plugin_returned) - self.manager = cm.get_event_plugin_manager() - self.manager.extensions = [self.plugin_loaded] - - def test_get_plugin_by_name(self): - self.assertEqual(self.plugin_returned, - self.manager.get_plugin_by_name(self.plugin_name)) - - def test_notify_ca_is_unavailable(self): - self.manager.notify_ca_is_unavailable( - self.project_id, - self.order_ref, - self.error_msg, - self.retry_in_msec) - - self.plugin_returned.notify_ca_is_unavailable.assert_called_once_with( - self.project_id, - self.order_ref, - self.error_msg, - self.retry_in_msec) - - def test_notify_certificate_is_ready(self): - self.manager.notify_certificate_is_ready( - self.project_id, - self.order_ref, - self.container_ref) - - pr = self.plugin_returned - pr.notify_certificate_is_ready.assert_called_once_with( - self.project_id, - self.order_ref, - self.container_ref) - - def test_invoke_certificate_plugins(self): - self.manager._invoke_certificate_plugins( - 'test_invoke_certificate_plugins', - self.project_id, - self.order_ref, - self.container_ref) - - # The _invoke_certificate_plugins method should invoke on - # self.plugin_returned the same method by name as the function - # that invoked it...in this case it is this test method. - pr = self.plugin_returned - pr.test_invoke_certificate_plugins.assert_called_once_with( - self.project_id, - self.order_ref, - self.container_ref) - - def test_raises_error_with_no_plugin_by_name_found(self): - self.manager.extensions = [] - self.assertRaises( - cm.CertificateEventPluginNotFound, - self.manager.get_plugin_by_name, - 'any-name-here' - ) - - def test_raises_error_with_no_plugin_for_invoke_certificate_plugins(self): - self.manager.extensions = [] - self.assertRaises( - cm.CertificateEventPluginNotFound, - self.manager._invoke_certificate_plugins, - self.project_id, - self.order_ref, - self.error_msg, - self.retry_in_msec, - ) - - -class WhenTestingCertificatePluginManager(database_utils.RepositoryTestCase, - utils.MockModelRepositoryMixin): - - def setUp(self): - super(WhenTestingCertificatePluginManager, self).setUp() - self.cert_spec = {} - - self.plugin_returned = mock.MagicMock() - self.plugin_name = common_utils.generate_fullname_for( - self.plugin_returned) - types_list = [cm.CertificateRequestType.SIMPLE_CMC_REQUEST, - cm.CertificateRequestType.CUSTOM_REQUEST] - self.plugin_returned.supported_request_types.return_value = types_list - self.plugin_returned.supports.return_value = True - self.plugin_loaded = mock.MagicMock(obj=self.plugin_returned) - - expiration = (datetime.datetime.utcnow() + datetime.timedelta( - days=cm.CA_INFO_DEFAULT_EXPIRATION_DAYS)) - ca_info = { - cm.INFO_NAME: "my_ca", - cm.INFO_DESCRIPTION: "Certificate Authority my_ca", - cm.INFO_CA_SIGNING_CERT: "Undefined", - cm.INFO_INTERMEDIATES: "Undefined", - cm.INFO_EXPIRATION: expiration.isoformat() - } - self.plugin_returned.get_ca_info.return_value = { - 'plugin_ca_id1': ca_info - } - - parsed_ca = { - 'plugin_name': self.plugin_name, - 'plugin_ca_id': 'plugin_ca_id1', - 'name': self.plugin_name, - 'description': 'Master CA for default plugin', - 'ca_signing_certificate': 'ZZZZZ', - 'intermediates': 'YYYYY' - } - self.ca = models.CertificateAuthority(parsed_ca) - self.ca.id = 'ca_id' - - self.ca_repo = mock.MagicMock() - self.ca_repo.get_by_create_date.return_value = ( - self.ca, 0, 1, 1) - self.ca_repo.create_from.return_value = None - self.ca_repo.get.return_value = self.ca - - self.project = models.Project() - self.project.id = '12345' - - self.setup_ca_repository_mock(self.ca_repo) - - self.plugin_loaded = mock.MagicMock(obj=self.plugin_returned) - self.manager = cm.CertificatePluginManager() - self.manager.extensions = [self.plugin_loaded] - - def test_get_plugin_by_name(self): - self.assertEqual(self.plugin_returned, - self.manager.get_plugin_by_name(self.plugin_name)) - - def test_get_plugin_by_ca_id(self): - self.assertEqual(self.plugin_returned, - self.manager.get_plugin_by_ca_id('ca_id')) - - def test_raises_error_with_no_plugin_by_ca_id_found(self): - self.ca_repo.get.return_value = None - self.assertRaises( - cm.CertificatePluginNotFoundForCAID, - self.manager.get_plugin_by_ca_id, - 'any-name-here' - ) - - def test_raises_error_with_no_plugin_by_name_found(self): - self.manager.extensions = [] - self.assertRaises( - cm.CertificatePluginNotFound, - self.manager.get_plugin_by_name, - 'any-name-here' - ) - - def test_get_plugin_no_request_type_provided(self): - # no request_type defaults to "custom" - self.assertEqual(self.plugin_returned, - self.manager.get_plugin(self.cert_spec)) - - def test_get_plugin_request_type_supported(self): - self.cert_spec = { - cm.REQUEST_TYPE: cm.CertificateRequestType.SIMPLE_CMC_REQUEST} - self.assertEqual(self.plugin_returned, - self.manager.get_plugin(self.cert_spec)) - - def test_raises_error_get_plugin_request_type_not_supported(self): - self.cert_spec = { - cm.REQUEST_TYPE: cm.CertificateRequestType.FULL_CMC_REQUEST} - self.assertRaises( - cm.CertificatePluginNotFound, - self.manager.get_plugin, - self.cert_spec - ) - - def test_raises_error_with_no_plugin_found(self): - self.manager.extensions = [] - self.assertRaises( - cm.CertificatePluginNotFound, - self.manager.get_plugin, - self.cert_spec - ) - - def test_get_plugin_with_ca_to_be_added(self): - self.ca_repo.get_by_create_date.return_value = ( - None, 0, 1, 0) - - self.assertEqual(self.plugin_returned, - self.manager.get_plugin(self.cert_spec)) - - def test_refresh_ca_list(self): - utc_now = datetime.datetime.utcnow() - expired_time = utc_now - datetime.timedelta(days=1) - expiration = utc_now + datetime.timedelta(days=1) - - ca1_info = { - cm.INFO_NAME: "expired_ca_to_be_modified", - cm.INFO_DESCRIPTION: "expired_ca to be modified", - cm.INFO_CA_SIGNING_CERT: "XXXXXXX-expired-XXXXXX", - cm.INFO_INTERMEDIATES: "YYYYYYY-expired-YYYYYYY", - cm.INFO_EXPIRATION: expired_time.isoformat() - } - - ca1_modified_info = { - cm.INFO_NAME: "expired_ca_to_be_modified", - cm.INFO_DESCRIPTION: "expired_ca to be modified", - cm.INFO_CA_SIGNING_CERT: "XXXXXXX-no-longer-expired-XXXXXX", - cm.INFO_INTERMEDIATES: "YYYYYYY-no-longer-expired-YYYYYYY", - cm.INFO_EXPIRATION: expiration.isoformat() - } - - ca2_info = { - cm.INFO_NAME: "expired_ca_to_be_deleted", - cm.INFO_DESCRIPTION: "expired ca to be deleted", - cm.INFO_CA_SIGNING_CERT: "XXXX-expired-to-be-deleted-XXXX", - cm.INFO_INTERMEDIATES: "YYYY-expired-to-be-deleted-YYYY", - cm.INFO_EXPIRATION: expired_time.isoformat() - } - - ca3_info = { - cm.INFO_NAME: "new-ca-to-be-added", - cm.INFO_DESCRIPTION: "new-ca-to-be-added", - cm.INFO_CA_SIGNING_CERT: "XXXX-to-be-addeed-XXXX", - cm.INFO_INTERMEDIATES: "YYYY-to-be-added-YYYY", - cm.INFO_EXPIRATION: expiration.isoformat() - } - - self.plugin_returned.get_ca_info.return_value = { - 'plugin_ca_id_ca1': ca1_modified_info, - 'plugin_ca_id_ca3': ca3_info - } - - parsed_ca1 = dict(ca1_info) - parsed_ca1[cm.PLUGIN_CA_ID] = 'plugin_ca_id_ca1' - parsed_ca1['plugin_name'] = self.plugin_name - ca1 = models.CertificateAuthority(parsed_ca1) - ca1.id = "ca1_id" - - parsed_ca2 = dict(ca2_info) - parsed_ca2[cm.PLUGIN_CA_ID] = 'plugin_ca_id_ca2' - parsed_ca2['plugin_name'] = self.plugin_name - ca2 = models.CertificateAuthority(parsed_ca2) - ca2.id = "ca2_id" - - side_effect = [(None, 0, 4, 0), - ([ca1, ca2], 0, 4, 2)] - self.ca_repo.get_by_create_date.side_effect = side_effect - - self.manager.refresh_ca_table() - self.plugin_returned.get_ca_info.assert_called_once_with() - self.ca_repo.update_entity.assert_called_once_with( - ca1, - ca1_modified_info) - - self.ca_repo.delete_entity_by_id.assert_called_once_with( - ca2.id, - None) - self.ca_repo.create_from.assert_has_calls([]) - - def test_refresh_ca_list_plugin_when_get_ca_info_raises(self): - self.ca_repo.get_by_create_date.return_value = (None, 0, 4, 0) - self.plugin_returned.get_ca_info.side_effect = Exception() - - self.manager.refresh_ca_table() - - self.plugin_returned.get_ca_info.assert_called_once_with() - - def test_refresh_ca_list_with_bad_ca_returned_from_plugin(self): - - ca3_info = { - cm.INFO_DESCRIPTION: "PLUGIN FAIL: this-ca-has-no-info", - } - - self.plugin_returned.get_ca_info.return_value = { - 'plugin_ca_id_ca3': ca3_info - } - - self.ca_repo.get_by_create_date.return_value = (None, 0, 4, 0) - self.ca_repo.create_from.side_effect = Exception() - - self.manager.refresh_ca_table() - - self.plugin_returned.get_ca_info.assert_called_once_with() - self.ca_repo.create_from.assert_has_calls([]) diff --git a/barbican/tests/plugin/test_dogtag.py b/barbican/tests/plugin/test_dogtag.py index 2464955c7..4ee0f1c11 100644 --- a/barbican/tests/plugin/test_dogtag.py +++ b/barbican/tests/plugin/test_dogtag.py @@ -13,8 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import base64 -import datetime import os import tempfile from unittest import mock @@ -22,19 +20,14 @@ from unittest import mock from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization -from requests import exceptions as request_exceptions import testtools -from barbican.tests import keys from barbican.tests import utils try: import barbican.plugin.dogtag as dogtag_import - import barbican.plugin.interface.certificate_manager as cm import barbican.plugin.interface.secret_store as sstore - import pki - import pki.cert as dogtag_cert import pki.key as dogtag_key imports_ok = True except ImportError: @@ -276,678 +269,3 @@ class WhenTestingDogtagKRAPlugin(utils.BaseTestCase): self.assertFalse( self.plugin.generate_supports(key_spec) ) - - -@testtools.skipIf(not imports_ok, "Dogtag imports not available") -class WhenTestingDogtagCAPlugin(utils.BaseTestCase): - - def setUp(self): - super(WhenTestingDogtagCAPlugin, self).setUp() - self.certclient_mock = mock.MagicMock(name="CertClient mock") - self.patcher = mock.patch('pki.crypto.NSSCryptoProvider') - self.patcher2 = mock.patch('pki.client.PKIConnection') - self.patcher.start() - self.patcher2.start() - - # create nss db for test only - self.nss_dir = tempfile.mkdtemp() - - # create expiration file for test - fh, self.expiration_data_path = tempfile.mkstemp() - exp_time = datetime.datetime.utcnow() + datetime.timedelta(days=2) - os.write(fh, exp_time.strftime( - "%Y-%m-%d %H:%M:%S.%f")) - os.close(fh) - - # create host CA file for test - fh, self.host_ca_path = tempfile.mkstemp() - os.write(fh, "host_ca_aid") - os.close(fh) - - self.approved_profile_id = "caServerCert" - CONF = dogtag_import.CONF - CONF.dogtag_plugin.nss_db_path = self.nss_dir - CONF.dogtag_plugin.ca_expiration_data_path = self.expiration_data_path - CONF.dogtag_plugin.ca_host_aid_path = self.host_ca_path - CONF.dogtag_plugin.auto_approved_profiles = [self.approved_profile_id] - CONF.dogtag_plugin.dogtag_host = "localhost" - CONF.dogtag_plugin.dogtag_port = 8443 - CONF.dogtag_plugin.simple_cmc_profile = "caOtherCert" - self.cfg = CONF - - self.plugin = dogtag_import.DogtagCAPlugin(CONF) - self.plugin.certclient = self.certclient_mock - self.order_id = mock.MagicMock() - self.profile_id = mock.MagicMock() - - # request generated - self.request_id_mock = mock.MagicMock() - self.request = dogtag_cert.CertRequestInfo() - self.request.request_id = self.request_id_mock - self.request.request_status = dogtag_cert.CertRequestStatus.COMPLETE - self.cert_id_mock = mock.MagicMock() - self.request.cert_id = self.cert_id_mock - - # cert generated - self.cert = mock.MagicMock() - self.cert.encoded = keys.get_certificate_pem() - self.cert.pkcs7_cert_chain = keys.get_certificate_der() - - # for cancel/modify - self.review_response = mock.MagicMock() - - # modified request - self.modified_request = mock.MagicMock() - self.modified_request_id_mock = mock.MagicMock() - self.modified_request.request_id = self.modified_request_id_mock - self.modified_request.request_status = ( - dogtag_cert.CertRequestStatus.COMPLETE) - self.modified_request.cert_id = self.cert_id_mock - - self.barbican_meta_dto = cm.BarbicanMetaDTO() - - def tearDown(self): - super(WhenTestingDogtagCAPlugin, self).tearDown() - self.patcher2.stop() - self.patcher.stop() - os.rmdir(self.nss_dir) - os.remove(self.host_ca_path) - os.remove(self.expiration_data_path) - - def _process_approved_profile_request(self, order_meta, plugin_meta): - enrollment_result = dogtag_cert.CertEnrollmentResult( - self.request, self.cert) - enrollment_results = [enrollment_result] - self.certclient_mock.enroll_cert.return_value = enrollment_results - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.enroll_cert.assert_called_once_with( - self.approved_profile_id, - order_meta) - - self.assertEqual(cm.CertificateStatus.CERTIFICATE_GENERATED, - result_dto.status, - "result_dto status incorrect") - - self.assertEqual(base64.b64encode(keys.get_certificate_pem()), - result_dto.certificate) - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID) - ) - - def _process_non_approved_profile_request(self, order_meta, plugin_meta, - profile_id, inputs=None): - if inputs is None: - inputs = { - 'cert_request_type': 'pkcs10', - 'cert_request': base64.b64decode( - order_meta.get('request_data')) - } - - # mock CertRequestInfo - enrollment_result = dogtag_cert.CertRequestInfo() - enrollment_result.request_id = self.request_id_mock - enrollment_result.request_status = ( - dogtag_cert.CertRequestStatus.PENDING) - - # mock CertRequestInfoCollection - enrollment_results = dogtag_cert.CertRequestInfoCollection() - enrollment_results.cert_request_info_list = ( - [enrollment_result]) - - self.certclient_mock.create_enrollment_request.return_value = ( - enrollment_result) - self.certclient_mock.submit_enrollment_request.return_value = ( - enrollment_results) - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.create_enrollment_request.assert_called_once_with( - profile_id, inputs) - - self.certclient_mock.submit_enrollment_request.assert_called_once_with( - enrollment_result) - - self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, - result_dto.status, - "result_dto status incorrect") - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID) - ) - - def test_issue_simple_cmc_request(self): - order_meta = { - cm.REQUEST_TYPE: cm.CertificateRequestType.SIMPLE_CMC_REQUEST, - 'request_data': base64.b64encode(keys.get_csr_pem()) - } - plugin_meta = {} - self._process_non_approved_profile_request( - order_meta, - plugin_meta, - self.cfg.dogtag_plugin.simple_cmc_profile) - - def test_issue_full_cmc_request(self): - order_meta = { - cm.REQUEST_TYPE: cm.CertificateRequestType.FULL_CMC_REQUEST, - 'request_data': 'Full CMC data ...' - } - plugin_meta = {} - - self.assertRaises( - dogtag_import.DogtagPluginNotSupportedException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_issue_stored_key_request(self): - order_meta = { - cm.REQUEST_TYPE: cm.CertificateRequestType.STORED_KEY_REQUEST, - 'request_data': base64.b64encode(keys.get_csr_pem()) - } - plugin_meta = {} - self._process_non_approved_profile_request( - order_meta, - plugin_meta, - self.cfg.dogtag_plugin.simple_cmc_profile) - - def test_issue_custom_key_request(self): - order_meta = { - cm.REQUEST_TYPE: cm.CertificateRequestType.CUSTOM_REQUEST, - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id, - } - plugin_meta = {} - self._process_approved_profile_request(order_meta, plugin_meta) - - def test_issue_no_cert_request_type_provided(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - self._process_approved_profile_request(order_meta, plugin_meta) - - def test_issue_bad_cert_request_type_provided(self): - order_meta = { - cm.REQUEST_TYPE: 'BAD_REQUEST_TYPE', - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.profile_id, - } - plugin_meta = {} - - self.assertRaises( - dogtag_import.DogtagPluginNotSupportedException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_issue_return_data_error_with_no_profile_id(self): - order_meta = {} - plugin_meta = {} - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.assertEqual(result_dto.status, - cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - "result_dto status incorrect") - - self.assertEqual(result_dto.status_message, - "No profile_id specified") - - def test_issue_return_data_error_with_request_rejected(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - self.request.request_status = dogtag_cert.CertRequestStatus.REJECTED - - enrollment_result = dogtag_cert.CertEnrollmentResult( - self.request, None) - enrollment_results = [enrollment_result] - self.certclient_mock.enroll_cert.return_value = enrollment_results - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.enroll_cert.assert_called_once_with( - self.approved_profile_id, - order_meta) - - self.assertEqual(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - result_dto.status, - "result_dto status incorrect") - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID)) - - def test_issue_return_canceled_with_request_canceled(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - self.request.request_status = dogtag_cert.CertRequestStatus.CANCELED - - enrollment_result = dogtag_cert.CertEnrollmentResult( - self.request, None) - enrollment_results = [enrollment_result] - self.certclient_mock.enroll_cert.return_value = enrollment_results - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.enroll_cert.assert_called_once_with( - self.approved_profile_id, - order_meta) - - self.assertEqual(cm.CertificateStatus.REQUEST_CANCELED, - result_dto.status, - "result_dto status incorrect") - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID), - ) - - def test_issue_return_waiting_with_request_pending(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: "otherProfile", - 'cert_request': base64.b64encode(keys.get_csr_pem())} - plugin_meta = {} - inputs = { - 'cert_request': keys.get_csr_pem(), - dogtag_import.DogtagCAPlugin.PROFILE_ID: "otherProfile" - } - self._process_non_approved_profile_request( - order_meta, plugin_meta, "otherProfile", inputs) - - def test_issue_raises_error_request_complete_no_cert(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - - enrollment_result = dogtag_cert.CertEnrollmentResult( - self.request, None) - enrollment_results = [enrollment_result] - self.certclient_mock.enroll_cert.return_value = enrollment_results - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID) - ) - - def test_issue_raises_error_request_unknown_status(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - - self.request.request_status = "unknown_status" - enrollment_result = dogtag_cert.CertEnrollmentResult( - self.request, None) - enrollment_results = [enrollment_result] - self.certclient_mock.enroll_cert.return_value = enrollment_results - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - self.assertEqual( - self.request_id_mock, - plugin_meta.get(dogtag_import.DogtagCAPlugin.REQUEST_ID) - ) - - def test_issue_return_client_error_bad_request_exception(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - - self.certclient_mock.enroll_cert.side_effect = ( - pki.BadRequestException("bad request")) - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.enroll_cert.assert_called_once_with( - self.approved_profile_id, - order_meta) - - self.assertEqual(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - result_dto.status, - "result_dto status incorrect") - - def test_issue_raises_error_pki_exception(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - - self.certclient_mock.enroll_cert.side_effect = ( - pki.PKIException("generic enrollment error")) - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_issue_return_ca_unavailable(self): - order_meta = { - dogtag_import.DogtagCAPlugin.PROFILE_ID: self.approved_profile_id} - plugin_meta = {} - - self.certclient_mock.enroll_cert.side_effect = ( - request_exceptions.RequestException()) - - result_dto = self.plugin.issue_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.enroll_cert.assert_called_once_with( - self.approved_profile_id, - order_meta) - - self.assertEqual(cm.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST, - result_dto.status, - "result_dto status incorrect") - - def test_cancel_request(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.cancel_request.return_value = None - self.certclient_mock.review_request.return_value = self.review_response - - result_dto = self.plugin.cancel_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.cancel_request.assert_called_once_with( - self.request_id_mock, - self.review_response) - - self.assertEqual(cm.CertificateStatus.REQUEST_CANCELED, - result_dto.status, - "result_dto_status incorrect") - - def test_cancel_no_request_found(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.side_effect = ( - pki.RequestNotFoundException("request_not_found")) - - result_dto = self.plugin.cancel_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.review_request.assert_called_once_with( - self.request_id_mock) - - self.assertEqual(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - result_dto.status, - "result_dto_status incorrect") - - def test_cancel_conflicting_operation(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.return_value = self.review_response - self.certclient_mock.cancel_request.side_effect = ( - pki.ConflictingOperationException("conflicting_operation")) - - result_dto = self.plugin.cancel_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.cancel_request.assert_called_once_with( - self.request_id_mock, - self.review_response) - - self.assertEqual(cm.CertificateStatus.INVALID_OPERATION, - result_dto.status, - "result_dto_status incorrect") - - def test_cancel_ca_unavailable(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.side_effect = ( - request_exceptions.RequestException("request_exception")) - - result_dto = self.plugin.cancel_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.assertEqual(cm.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST, - result_dto.status, - "result_dto_status incorrect") - - def test_cancel_raise_error_no_request_id(self): - order_meta = mock.ANY - plugin_meta = {} - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.cancel_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_check_status(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.get_request.return_value = self.request - self.certclient_mock.get_cert.return_value = self.cert - - result_dto = self.plugin.check_certificate_status( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.get_request.assert_called_once_with( - self.request_id_mock) - - self.certclient_mock.get_cert.assert_called_once_with( - self.cert_id_mock) - - self.assertEqual(cm.CertificateStatus.CERTIFICATE_GENERATED, - result_dto.status, - "result_dto_status incorrect") - - self.assertEqual(keys.get_certificate_pem(), - result_dto.certificate) - - def test_check_status_raise_error_no_request_id(self): - order_meta = mock.ANY - plugin_meta = {} - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.check_certificate_status, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_check_status_rejected(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.request.request_status = dogtag_cert.CertRequestStatus.REJECTED - self.certclient_mock.get_request.return_value = self.request - - result_dto = self.plugin.check_certificate_status( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.get_request.assert_called_once_with( - self.request_id_mock) - - self.assertEqual(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - result_dto.status, - "result_dto_status incorrect") - - self.assertIsNone(result_dto.certificate) - - def test_check_status_canceled(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.request.request_status = dogtag_cert.CertRequestStatus.CANCELED - self.certclient_mock.get_request.return_value = self.request - - result_dto = self.plugin.check_certificate_status( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.get_request.assert_called_once_with( - self.request_id_mock) - - self.assertEqual(cm.CertificateStatus.REQUEST_CANCELED, - result_dto.status, - "result_dto_status incorrect") - - self.assertIsNone(result_dto.certificate) - - def test_check_status_pending(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.request.request_status = dogtag_cert.CertRequestStatus.PENDING - self.certclient_mock.get_request.return_value = self.request - - result_dto = self.plugin.check_certificate_status( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.get_request.assert_called_once_with( - self.request_id_mock) - - self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, - result_dto.status, - "result_dto_status incorrect") - - self.assertIsNone(result_dto.certificate) - - def test_check_status_raises_error_complete_no_cert(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.get_request.return_value = self.request - self.certclient_mock.get_cert.return_value = None - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.check_certificate_status, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) - - def test_modify_request(self): - order_meta = { - cm.REQUEST_TYPE: cm.CertificateRequestType.SIMPLE_CMC_REQUEST, - 'request_data': base64.b64encode(keys.get_csr_pem()) - } - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self._process_non_approved_profile_request( - order_meta, - plugin_meta, - self.cfg.dogtag_plugin.simple_cmc_profile) - - self.certclient_mock.cancel_request.return_value = None - self.certclient_mock.review_request.return_value = self.review_response - - result_dto = self.plugin.modify_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.cancel_request.assert_called_once_with( - self.request_id_mock, - self.review_response) - - self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, - result_dto.status, - "result_dto_status incorrect") - - def test_modify_no_request_found(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.side_effect = ( - pki.RequestNotFoundException("request_not_found")) - - result_dto = self.plugin.modify_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.review_request.assert_called_once_with( - self.request_id_mock) - - self.assertEqual(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - result_dto.status, - "result_dto_status incorrect") - - def test_modify_conflicting_operation(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.return_value = self.review_response - self.certclient_mock.cancel_request.side_effect = ( - pki.ConflictingOperationException("conflicting_operation")) - - result_dto = self.plugin.modify_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.certclient_mock.cancel_request.assert_called_once_with( - self.request_id_mock, - self.review_response) - - self.assertEqual(cm.CertificateStatus.INVALID_OPERATION, - result_dto.status, - "result_dto_status incorrect") - - def test_modify_ca_unavailable(self): - order_meta = mock.ANY - plugin_meta = {dogtag_import.DogtagCAPlugin.REQUEST_ID: - self.request_id_mock} - self.certclient_mock.review_request.side_effect = ( - request_exceptions.RequestException("request_exception")) - - result_dto = self.plugin.modify_certificate_request( - self.order_id, order_meta, plugin_meta, self.barbican_meta_dto) - - self.assertEqual(cm.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST, - result_dto.status, - "result_dto_status incorrect") - - def test_modify_raise_error_no_request_id(self): - order_meta = mock.ANY - plugin_meta = {} - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.modify_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto - ) diff --git a/barbican/tests/plugin/test_simple_certificate_manager.py b/barbican/tests/plugin/test_simple_certificate_manager.py deleted file mode 100644 index 3683be786..000000000 --- a/barbican/tests/plugin/test_simple_certificate_manager.py +++ /dev/null @@ -1,83 +0,0 @@ -# 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 testtools - -import barbican.plugin.interface.certificate_manager as cm -import barbican.plugin.simple_certificate_manager as simple - - -class WhenTestingSimpleCertificateManagerPlugin(testtools.TestCase): - - def setUp(self): - super(WhenTestingSimpleCertificateManagerPlugin, self).setUp() - self.plugin = simple.SimpleCertificatePlugin() - - def test_issue_certificate_request(self): - result = self.plugin.issue_certificate_request(None, None, None, None) - - self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, result.status) - - def test_check_certificate_status(self): - result = self.plugin.check_certificate_status(None, None, None, None) - - self.assertEqual( - cm.CertificateStatus.CERTIFICATE_GENERATED, result.status) - - def test_modify_certificate_request(self): - result = self.plugin.modify_certificate_request(None, None, None, None) - - self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, result.status) - - def test_cancel_certificate_request(self): - result = self.plugin.cancel_certificate_request(None, None, None, None) - - self.assertEqual(cm.CertificateStatus.REQUEST_CANCELED, result.status) - - def test_supports(self): - result = self.plugin.supports(None) - - self.assertTrue(result) - - def test_get_ca_info(self): - result = self.plugin.get_ca_info() - name = self.plugin.get_default_ca_name() - self.assertIn(name, result) - self.assertEqual(name, result[name][cm.INFO_NAME]) - self.assertEqual(self.plugin.get_default_signing_cert(), - result[name][cm.INFO_CA_SIGNING_CERT]) - - def test_supported_request_types(self): - result = self.plugin.supported_request_types() - supported_list = [cm.CertificateRequestType.CUSTOM_REQUEST, - cm.CertificateRequestType.SIMPLE_CMC_REQUEST, - cm.CertificateRequestType.FULL_CMC_REQUEST, - cm.CertificateRequestType.STORED_KEY_REQUEST] - self.assertEqual(supported_list, result) - - -class WhenTestingSimpleCertificateEventManagerPlugin(testtools.TestCase): - - def setUp(self): - super(WhenTestingSimpleCertificateEventManagerPlugin, self).setUp() - self.plugin = simple.SimpleCertificateEventPlugin() - - def test_notify_ca_is_unavailable(self): - # Test that eventing plugin method does not have side effects such as - # raising exceptions. - self.plugin.notify_ca_is_unavailable(None, None, None, None) - - def test_notify_certificate_is_ready(self): - # Test that eventing plugin method does not have side effects such as - # raising exceptions. - self.plugin.notify_certificate_is_ready(None, None, None) diff --git a/barbican/tests/plugin/test_snakeoil_ca.py b/barbican/tests/plugin/test_snakeoil_ca.py deleted file mode 100644 index e14ee6f52..000000000 --- a/barbican/tests/plugin/test_snakeoil_ca.py +++ /dev/null @@ -1,453 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 base64 -import os -from unittest import mock - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.serialization import pkcs7 -from cryptography import x509 -import fixtures -from OpenSSL import crypto -from oslo_config import fixture as oslo_fixture - -import barbican.plugin.interface.certificate_manager as cm -from barbican.plugin import snakeoil_ca -from barbican.tests import certificate_utils -from barbican.tests import utils - - -class BaseTestCase(utils.BaseTestCase): - - def setUp(self): - super(BaseTestCase, self).setUp() - self.conf = self.useFixture(oslo_fixture.Config( - conf=snakeoil_ca.CONF)).conf - self.tmp_dir = self.useFixture(fixtures.TempDir()).path - - def tearDown(self): - super(BaseTestCase, self).tearDown() - - -class CaTestCase(BaseTestCase): - - def test_gen_cacert_no_file_storage(self): - subject_dn = ( - 'cn=Test CN,o=Test O,L=Test L,st=Test ST,ou=Test OU' - ) - ca = snakeoil_ca.SnakeoilCA(cert_path=None, key_path=None, - key_size=512, subject_dn=subject_dn) - subject = ca.cert.get_subject() - self.assertIsNotNone(ca.key) - self.assertEqual("Test ST", subject.ST) - self.assertEqual("Test L", subject.L) - self.assertEqual("Test O", subject.O) - self.assertEqual("Test CN", subject.CN) - self.assertEqual("Test OU", subject.OU) - self.assertEqual( - ca.chain, - crypto.dump_certificate(crypto.FILETYPE_PEM, ca.cert)) - - def test_gen_cacert_with_file_storage(self): - cert_path = self.tmp_dir + 'cert.pem' - key_path = self.tmp_dir + 'key.pem' - chain_path = self.tmp_dir + 'cert.chain' - pkcs7_path = self.tmp_dir + 'cert.p7b' - - subject_dn = 'cn=Test CN,o=Test O,L=Test L,st=Test ST' - ca = snakeoil_ca.SnakeoilCA( - cert_path=cert_path, - key_path=key_path, - chain_path=chain_path, - pkcs7_path=pkcs7_path, - key_size=2048, - subject_dn=subject_dn) - - subject = ca.cert.get_subject() - self.assertEqual( - ca.chain, - crypto.dump_certificate(crypto.FILETYPE_PEM, ca.cert)) - self.assertIsNotNone(ca.key) - self.assertEqual("Test ST", subject.ST) - self.assertEqual("Test L", subject.L) - self.assertEqual("Test O", subject.O) - self.assertEqual("Test CN", subject.CN) - - # Make sure we preserve existing keypairs - ca = snakeoil_ca.SnakeoilCA( - cert_path=cert_path, - key_path=key_path, - chain_path=chain_path, - pkcs7_path=pkcs7_path - ) - subject = ca.cert.get_subject() - self.assertEqual("Test ST", subject.ST) - self.assertEqual("Test L", subject.L) - self.assertEqual("Test O", subject.O) - self.assertEqual("Test CN", subject.CN) - - def test_gen_sub_cacert_with_file_storage(self): - cert_path = self.tmp_dir + 'cert.pem' - key_path = self.tmp_dir + 'key.pem' - chain_path = self.tmp_dir + 'cert.chain' - pkcs7_path = self.tmp_dir + 'cert.p7b' - - subject_dn = 'cn=Test CN,o=Test O,L=Test L,st=Test ST' - parent_ca = snakeoil_ca.SnakeoilCA( - cert_path=cert_path, - key_path=key_path, - chain_path=chain_path, - pkcs7_path=pkcs7_path, - key_size=2048, - subject_dn=subject_dn) - self.assertIsNotNone(parent_ca) - - # create a sub-ca - subject_dn = 'cn=Sub CA Test CN,o=Test O,L=Test L,st=Test ST' - cert_path = self.tmp_dir + 'sub_cert.pem' - key_path = self.tmp_dir + 'sub_key.pem' - chain_path = self.tmp_dir + 'sub_cert.chain' - pkcs7_path = self.tmp_dir + 'sub_cert.p7b' - - sub_ca = snakeoil_ca.SnakeoilCA( - cert_path=cert_path, - key_path=key_path, - chain_path=chain_path, - pkcs7_path=pkcs7_path, - key_size=2048, - subject_dn=subject_dn, - parent_chain_path=parent_ca.chain_path, - signing_dn=parent_ca.subject_dn, - signing_key=parent_ca.key - ) - - subject = sub_ca.cert.get_subject() - self.assertEqual("Test ST", subject.ST) - self.assertEqual("Test L", subject.L) - self.assertEqual("Test O", subject.O) - self.assertEqual("Sub CA Test CN", subject.CN) - - -class CertManagerTestCase(BaseTestCase): - - def setUp(self): - super(CertManagerTestCase, self).setUp() - subject_dn = 'cn=Test CN,o=Test O,L=Test L,st=Test ST' - self.ca = snakeoil_ca.SnakeoilCA(cert_path=None, key_path=None, - key_size=512, subject_dn=subject_dn) - - def verify_sig(self, encoded_cert): - cert = x509.load_der_x509_certificate(encoded_cert, default_backend()) - - crypto.verify( - self.ca.cert, - cert.signature, - cert.tbs_certificate_bytes, - 'sha256') - - def test_gen_cert_no_file_storage(self): - req = certificate_utils.get_valid_csr_object() - - cm = snakeoil_ca.CertManager(self.ca) - cert = cm.make_certificate(req) - first_serial = cert.get_serial_number() - cert_enc = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert) - self.verify_sig(cert_enc) - - cert = cm.make_certificate(req) - self.assertNotEqual(first_serial, cert.get_serial_number()) - self.verify_sig(cert_enc) - - cm = snakeoil_ca.CertManager(self.ca) - cert = cm.make_certificate(req) - - def test_gen_cert_with_file_storage(self): - req = certificate_utils.get_valid_csr_object() - - cm = snakeoil_ca.CertManager(self.ca) - cert = cm.make_certificate(req) - cert_enc = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert) - first_serial = cert.get_serial_number() - self.verify_sig(cert_enc) - - cm = snakeoil_ca.CertManager(self.ca) - cert = cm.make_certificate(req) - self.assertNotEqual(first_serial, cert.get_serial_number()) - - -class SnakeoilCAPluginTestCase(BaseTestCase): - - def setUp(self): - super(SnakeoilCAPluginTestCase, self).setUp() - self.ca_cert_path = os.path.join(self.tmp_dir, 'ca.cert') - self.ca_key_path = os.path.join(self.tmp_dir, 'ca.key') - self.ca_chain_path = os.path.join(self.tmp_dir, 'ca.chain') - self.ca_pkcs7_path = os.path.join(self.tmp_dir, 'ca.pkcs7') - self.db_dir = self.tmp_dir - - self.conf.snakeoil_ca_plugin.subca_cert_key_directory = os.path.join( - self.tmp_dir, 'subca_cert_key_dir') - self.subca_cert_key_directory = ( - self.conf.snakeoil_ca_plugin.subca_cert_key_directory) - - self.plugin = snakeoil_ca.SnakeoilCACertificatePlugin( - self.conf) - self.order_id = mock.MagicMock() - self.barbican_meta_dto = cm.BarbicanMetaDTO() - - def test_issue_certificate_request(self): - req = certificate_utils.get_valid_csr_object() - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - req_enc = base64.b64encode(req_enc) - order_meta = {'request_data': req_enc} - resp = self.plugin.issue_certificate_request(self.order_id, - order_meta, {}, - self.barbican_meta_dto) - crypto.load_certificate( - crypto.FILETYPE_PEM, base64.b64decode(resp.certificate)) - - def test_issue_certificate_request_with_ca_id(self): - req = certificate_utils.get_valid_csr_object() - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - req_enc = base64.b64encode(req_enc) - order_meta = {'request_data': req_enc} - plugin_meta = {'plugin_ca_id': self.plugin.get_default_ca_name()} - self.barbican_meta_dto.plugin_ca_id = self.plugin.get_default_ca_name() - resp = self.plugin.issue_certificate_request(self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto) - crypto.load_certificate( - crypto.FILETYPE_PEM, base64.b64decode(resp.certificate)) - - def test_issue_raises_with_invalid_ca_id(self): - req = certificate_utils.get_valid_csr_object() - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - req_enc = base64.b64encode(req_enc) - order_meta = {'request_data': req_enc} - plugin_meta = {'plugin_ca_id': "invalid_ca_id"} - self.barbican_meta_dto.plugin_ca_id = "invalid_ca_id" - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.issue_certificate_request, - self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto) - - def test_issue_certificate_request_set_subject(self): - req = certificate_utils.get_valid_csr_object() - - subj = req.get_subject() - subj.countryName = 'US' - subj.stateOrProvinceName = 'OR' - subj.localityName = 'Testlandia' - subj.organizationName = 'Testers Anon' - subj.organizationalUnitName = 'Testers OU' - subj.commonName = 'Testing' - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - req_enc = base64.b64encode(req_enc) - order_meta = {'request_data': req_enc} - resp = self.plugin.issue_certificate_request(self.order_id, - order_meta, {}, - self.barbican_meta_dto) - cert = crypto.load_certificate( - crypto.FILETYPE_PEM, base64.b64decode(resp.certificate)) - cert_subj = cert.get_subject() - self.assertEqual('US', cert_subj.C) - self.assertEqual('OR', cert_subj.ST) - self.assertEqual('Testlandia', cert_subj.L) - self.assertEqual('Testers Anon', cert_subj.O) - self.assertEqual('Testers OU', cert_subj.OU) - self.assertEqual('Testing', cert_subj.CN) - - def test_issue_certificate_request_stored_key(self): - req = certificate_utils.get_valid_csr_object() - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - self.barbican_meta_dto.generated_csr = req_enc - resp = self.plugin.issue_certificate_request( - self.order_id, {}, {}, self.barbican_meta_dto) - crypto.load_certificate( - crypto.FILETYPE_PEM, base64.b64decode(resp.certificate)) - - def test_no_request_data(self): - res = self.plugin.issue_certificate_request( - self.order_id, {}, {}, self.barbican_meta_dto) - self.assertIs(cm.CertificateStatus.CLIENT_DATA_ISSUE_SEEN, - res.status) - self.assertEqual("No request_data specified", res.status_message) - - def test_get_default_ca_name(self): - self.assertEqual("Snakeoil CA", self.plugin.get_default_ca_name()) - - def test_get_default_signing_cert(self): - ca_cert = self.plugin.get_default_signing_cert() - self.assertEqual( - crypto.dump_certificate(crypto.FILETYPE_PEM, self.plugin.ca.cert), - ca_cert) - - def test_get_default_intermediates_none(self): - intermediates = self.plugin.get_default_intermediates() - self.assertIsNone(intermediates) - - def test_not_implemented(self): - self.assertRaises(NotImplementedError, - self.plugin.modify_certificate_request, - '', {}, {}, {}) - self.assertRaises(NotImplementedError, - self.plugin.cancel_certificate_request, - '', {}, {}, {}) - self.assertRaises(NotImplementedError, - self.plugin.check_certificate_status, - '', {}, {}, {}) - - def test_support_request_types(self): - manager = cm.CertificatePluginManager() - manager.extensions = [mock.MagicMock(obj=self.plugin)] - cert_spec = { - cm.REQUEST_TYPE: cm.CertificateRequestType.CUSTOM_REQUEST} - self.assertEqual(self.plugin, manager.get_plugin(cert_spec)) - self.assertTrue(self.plugin.supports(cert_spec)) - cert_spec = { - cm.REQUEST_TYPE: cm.CertificateRequestType.STORED_KEY_REQUEST} - self.assertEqual(self.plugin, manager.get_plugin(cert_spec)) - self.assertTrue(self.plugin.supports(cert_spec)) - cert_spec = { - cm.REQUEST_TYPE: cm.CertificateRequestType.FULL_CMC_REQUEST} - self.assertRaises(cm.CertificatePluginNotFound, - manager.get_plugin, cert_spec) - self.assertFalse(self.plugin.supports(cert_spec)) - - def test_supports_create_ca(self): - self.assertTrue(self.plugin.supports_create_ca()) - - def _create_subca(self): - create_ca_dto = cm.CACreateDTO( - name="sub ca1", - description="subordinate ca", - subject_dn="cn=subordinate ca signing cert, o=example.com", - parent_ca_id=self.plugin.get_default_ca_name() - ) - return self.plugin.create_ca(create_ca_dto) - - def test_create_ca(self): - subca_dict = self._create_subca() - self.assertEqual("sub ca1", subca_dict.get(cm.INFO_NAME)) - self.assertIsNotNone(subca_dict.get(cm.INFO_EXPIRATION)) - self.assertIsNotNone(subca_dict.get(cm.PLUGIN_CA_ID)) - ca_cert = subca_dict.get(cm.INFO_CA_SIGNING_CERT) - self.assertIsNotNone(ca_cert) - - intermediates = subca_dict.get(cm.INFO_INTERMEDIATES) - self.assertIsNotNone(intermediates) - - cacert = crypto.load_certificate(crypto.FILETYPE_PEM, ca_cert) - subject = cacert.get_subject() - self.assertEqual( - "subordinate ca signing cert", - subject.CN) - - certs = pkcs7.load_pem_pkcs7_certificates(intermediates) - self.assertIsNotNone(certs[0].signature) - - # TODO(alee) Verify that ca cert is signed by parent CA - - def test_issue_certificate_request_with_subca_id(self): - subca_dict = self._create_subca() - req = certificate_utils.get_valid_csr_object() - - req_enc = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) - req_enc = base64.b64encode(req_enc) - order_meta = {'request_data': req_enc} - plugin_meta = {'plugin_ca_id': subca_dict.get(cm.PLUGIN_CA_ID)} - self.barbican_meta_dto.plugin_ca_id = subca_dict.get(cm.PLUGIN_CA_ID) - resp = self.plugin.issue_certificate_request(self.order_id, - order_meta, - plugin_meta, - self.barbican_meta_dto) - new_cert = crypto.load_certificate( - crypto.FILETYPE_PEM, base64.b64decode(resp.certificate)) - signing_cert = crypto.load_certificate( - crypto.FILETYPE_PEM, subca_dict['ca_signing_certificate']) - - self.assertEqual(signing_cert.get_subject(), new_cert.get_issuer()) - - def test_delete_ca(self): - subca_dict = self._create_subca() - ca_id = subca_dict.get(cm.PLUGIN_CA_ID) - self.assertIsNotNone(ca_id) - - cert_path = os.path.join(self.subca_cert_key_directory, - ca_id + ".cert") - key_path = os.path.join(self.subca_cert_key_directory, - ca_id + ".key") - self.assertTrue(os.path.exists(cert_path)) - self.assertTrue(os.path.exists(key_path)) - - self.plugin.delete_ca(ca_id) - self.assertFalse(os.path.exists(cert_path)) - self.assertFalse(os.path.exists(key_path)) - - cas = self.plugin.get_ca_info() - self.assertNotIn(ca_id, cas.keys()) - - def test_raises_no_parent_id_passed_in(self): - create_ca_dto = cm.CACreateDTO( - name="sub ca1", - description="subordinate ca", - subject_dn="cn=subordinate ca signing cert, o=example.com", - ) - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.create_ca, - create_ca_dto - ) - - def test_raises_invalid_parent_id_passed_in(self): - create_ca_dto = cm.CACreateDTO( - name="sub ca1", - description="subordinate ca", - subject_dn="cn=subordinate ca signing cert, o=example.com", - parent_ca_id="foo" - ) - - self.assertRaises( - cm.CertificateGeneralException, - self.plugin.create_ca, - create_ca_dto - ) - - def test_get_ca_info(self): - ca_info = self.plugin.get_ca_info() - ca_dict = ca_info.get(self.plugin.ca.name) - self.assertIsNotNone(ca_dict) - self.assertEqual(self.plugin.ca.name, ca_dict.get(cm.INFO_NAME)) - self.assertIsNotNone(ca_dict.get(cm.INFO_CA_SIGNING_CERT)) - self.assertEqual(str, type(ca_dict.get(cm.INFO_EXPIRATION))) - - def test_get_ca_info_with_subca(self): - subca_dict = self._create_subca() - subca_id = subca_dict.get(cm.PLUGIN_CA_ID) - ca_info = self.plugin.get_ca_info() - self.assertIn(subca_id, ca_info.keys()) - self.assertIn(self.plugin.get_default_ca_name(), ca_info.keys()) - self.assertEqual(str, type(subca_dict.get(cm.INFO_EXPIRATION))) diff --git a/barbican/tests/plugin/test_symantec.py b/barbican/tests/plugin/test_symantec.py deleted file mode 100644 index 8715e3138..000000000 --- a/barbican/tests/plugin/test_symantec.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) 2013-2014 Rackspace, Inc. -# -# 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 testtools -from unittest import mock - -try: - import barbican.plugin.interface.certificate_manager as cm - import barbican.plugin.symantec as sym - imports_ok = True -except ImportError: - # Symantec imports probably not available - imports_ok = False - -from barbican.tests import utils - - -@testtools.skipIf(not imports_ok, "Symantec imports not available") -class WhenTestingSymantecPlugin(utils.BaseTestCase): - - def setUp(self): - super(WhenTestingSymantecPlugin, self).setUp() - self.order_meta = { - 'cert_type': 'ssl123', - 'organization': 'Shinra Corp', - 'phone': '555-555-5555', - 'so many things...': 'more...' - } - - self.error_msg = 'Error Message Here' - self.symantec = sym.SymantecCertificatePlugin() - self.barbican_plugin_dto = cm.BarbicanMetaDTO() - - self.symantec_patcher = mock.patch( - 'barbican.plugin.symantec._ca_create_order' - ) - self.mock_create_order = self.symantec_patcher.start() - - def tearDown(self): - super(WhenTestingSymantecPlugin, self).tearDown() - if hasattr(self, 'mock_create_order'): - self.mock_create_order.stop() - - def test_successful_issue_certificate_request(self): - self.mock_create_order.return_value = (True, None, None) - - order_id = '1234' - plugin_meta = {} - - result = self.symantec.issue_certificate_request( - order_id, - self.order_meta, - plugin_meta, - self.barbican_plugin_dto - ) - - self.assertEqual("waiting for CA", result.status) - - def test_unsuccessful_certificate_request_can_retry(self): - self.mock_create_order.return_value = (False, self.error_msg, True) - - order_id = '1234' - plugin_meta = {} - - result = self.symantec.issue_certificate_request( - order_id, - self.order_meta, - plugin_meta, - self.barbican_plugin_dto - ) - - self.assertEqual("client data issue seen", result.status) - - def test_unsuccessful_certificate_request_no_retry(self): - self.mock_create_order.return_value = (False, self.error_msg, False) - - order_id = '12345' - plugin_meta = {} - - result = self.symantec.issue_certificate_request( - order_id, - self.order_meta, - plugin_meta, - self.barbican_plugin_dto - ) - - self.assertEqual("CA unavailable for request", result.status) - - def test_should_raise_unsupported_certificate_request(self): - order_id = '1234' - plugin_meta = {} - self.assertRaises( - NotImplementedError, - self.symantec.check_certificate_status, - order_id, - self.order_meta, - plugin_meta, - self.barbican_plugin_dto - ) diff --git a/barbican/tests/queue/test_server.py b/barbican/tests/queue/test_server.py index 25c1ed36b..4e32f3b7c 100644 --- a/barbican/tests/queue/test_server.py +++ b/barbican/tests/queue/test_server.py @@ -222,25 +222,6 @@ class WhenCallingScheduleOrderRetryTasks(database_utils.RepositoryTestCase): self.assertEqual( 'test_should_schedule_invoking_task_for_retry', retry_rpc_method) - def test_should_schedule_certificate_status_task_for_retry(self): - self.result.retry_task = ( - common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK - ) - - # Schedule this test method as the passed-in 'retry' function. - retry_rpc_method = server.schedule_order_retry_tasks( - None, # Should be ignored for non-self retries. - self.result, - None, # Not used. - *self.args, - **self.kwargs) - database_utils.get_session().commit() # Flush to the database. - - self.assertEqual( - 'check_certificate_status', retry_rpc_method) - self._verify_retry_task_entity( - 'check_certificate_status') - def _verify_retry_task_entity(self, retry_task): # Retrieve the task retry entity created above and verify it. entities, offset, limit, total = self.repo.get_by_create_date() @@ -302,24 +283,6 @@ class WhenCallingTasksMethod(utils.BaseTestCase): mock.ANY, 'result', None, 'order1234', 'keystone1234', 'request1234') - @mock.patch('barbican.queue.server.schedule_order_retry_tasks') - @mock.patch('barbican.tasks.resources.CheckCertificateStatusOrder') - def test_should_check_certificate_order( - self, mock_check_cert, mock_schedule): - method = mock_check_cert.return_value.process_and_suppress_exceptions - method.return_value = 'result' - - self.tasks.check_certificate_status( - None, self.order_id, self.external_project_id, self.request_id) - - mock_process = mock_check_cert.return_value - mock_process.process_and_suppress_exceptions.assert_called_with( - self.order_id, self.external_project_id - ) - mock_schedule.assert_called_with( - mock.ANY, 'result', None, 'order1234', - 'keystone1234', 'request1234') - @mock.patch('barbican.tasks.resources.BeginTypeOrder') def test_process_order_catch_exception(self, mock_begin_order): """Test that BeginTypeOrder's process() handles all exceptions.""" diff --git a/barbican/tests/tasks/test_certificate_resources.py b/barbican/tests/tasks/test_certificate_resources.py deleted file mode 100644 index dac76fbf0..000000000 --- a/barbican/tests/tasks/test_certificate_resources.py +++ /dev/null @@ -1,1124 +0,0 @@ -# Copyright (c) 2013-2014 Rackspace, Inc. -# -# 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 base64 -import datetime -from unittest import mock - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives import serialization -from OpenSSL import crypto -from oslo_utils import encodeutils - -from barbican.common import exception as excep -from barbican.common import hrefs -from barbican.common import resources as res -from barbican.model import models -from barbican.model import repositories -from barbican.plugin.interface import certificate_manager as cert_man -from barbican.plugin.interface import secret_store -from barbican.tasks import certificate_resources as cert_res -from barbican.tasks import common -from barbican.tests import database_utils -from barbican.tests import utils - -container_repo = repositories.get_container_repository() -secret_repo = repositories.get_secret_repository() -ca_repo = repositories.get_ca_repository() -project_ca_repo = repositories.get_project_ca_repository() -preferred_ca_repo = repositories.get_preferred_ca_repository() -project_repo = repositories.get_project_repository() -order_repo = repositories.get_order_repository() - - -class WhenPerformingPrivateOperations(utils.BaseTestCase, - utils.MockModelRepositoryMixin): - """Tests private methods within certificate_resources.py.""" - - def setUp(self): - super(WhenPerformingPrivateOperations, self).setUp() - self.order_plugin_meta_repo = mock.MagicMock() - self.setup_order_plugin_meta_repository_mock( - self.order_plugin_meta_repo) - self.order_barbican_meta_repo = mock.MagicMock() - self.setup_order_barbican_meta_repository_mock( - self.order_barbican_meta_repo) - - def test_get_plugin_meta(self): - class Value(object): - def __init__(self, value): - self.value = value - - class OrderModel(object): - id = mock.ANY - order_plugin_metadata = { - "foo": Value(1), - "bar": Value(2), - } - order_model = OrderModel() - self.order_plugin_meta_repo.get_metadata_for_order.return_value = ( - order_model.order_plugin_metadata - ) - result = cert_res._get_plugin_meta(order_model) - - self._assert_dict_equal(order_model.order_plugin_metadata, result) - - def test_get_plugin_meta_with_empty_dict(self): - result = cert_res._get_plugin_meta(None) - - self._assert_dict_equal({}, result) - - def test_save_plugin_meta_w_mock_meta(self): - # Test dict for plugin meta data. - test_order_model = 'My order model' - test_plugin_meta = {"foo": 1} - - cert_res._save_plugin_metadata( - test_order_model, test_plugin_meta) - - self.order_plugin_meta_repo.save.assert_called_once_with( - test_plugin_meta, test_order_model) - - def test_save_plugin_w_null_meta(self): - test_order_model = 'My order model' - - # Test None for plugin meta data. - cert_res._save_plugin_metadata( - test_order_model, None) - - self.order_plugin_meta_repo.save.assert_called_once_with( - {}, test_order_model) - - def test_get_barbican_meta_with_empty_dict(self): - result = cert_res._get_barbican_meta(None) - - self._assert_dict_equal({}, result) - - def test_save_barbican_w_null_meta(self): - test_order_model = 'My order model' - - # Test None for plugin meta data. - cert_res._save_barbican_metadata( - test_order_model, None) - - self.order_barbican_meta_repo.save.assert_called_once_with( - {}, test_order_model) - - def _assert_dict_equal(self, expected, test): - self.assertIsInstance(expected, dict) - self.assertIsInstance(test, dict) - - if expected != test: - if len(expected) != len(test): - self.fail('Expected dict not same size as test dict') - - unmatched_items = set(expected.items()) ^ set(test.items()) - if len(unmatched_items): - self.fail('One or more items different ' - 'between the expected and test dicts') - - -class BaseCertificateRequestsTestCase(database_utils.RepositoryTestCase): - """Base Certificate Case Test function """ - - def setUp(self): - super(BaseCertificateRequestsTestCase, self).setUp() - - self.external_project_id = "56789" - self.project = res.get_or_create_project(self.external_project_id) - project_repo.save(self.project) - - self.barbican_meta_dto = mock.MagicMock() - self.order_meta = {} - self.plugin_meta = {} - self.barbican_meta = {} - self.result = cert_man.ResultDTO( - cert_man.CertificateStatus.WAITING_FOR_CA - ) - self.result_follow_on = common.FollowOnProcessingStatusDTO() - - self.cert_plugin = mock.MagicMock() - self.cert_plugin.issue_certificate_request.return_value = self.result - self.cert_plugin.check_certificate_status.return_value = self.result - - self.store_plugin = mock.MagicMock() - - parsed_ca = { - 'plugin_name': "cert_plugin", - 'plugin_ca_id': "XXXX", - 'name': "test ca", - 'description': 'Test CA', - 'ca_signing_certificate': 'ZZZZZ', - 'intermediates': 'YYYYY' - } - - self.ca = models.CertificateAuthority(parsed_ca) - ca_repo.create_from(self.ca) - self.ca_id = self.ca.id - - # second ca for testing - parsed_ca = { - 'plugin_name': "cert_plugin", - 'plugin_ca_id': "XXXX2", - 'name': "test ca2", - 'description': 'Test CA2', - 'ca_signing_certificate': 'ZZZZZ2', - 'intermediates': 'YYYYY2' - } - - self.ca2 = models.CertificateAuthority(parsed_ca) - ca_repo.create_from(self.ca2) - self.ca_id2 = self.ca2.id - - # data for preferred CA and global preferred CA tests - # add those to the repo in those tests - self.pref_ca = models.PreferredCertificateAuthority( - self.project.id, - self.ca_id) - - self.global_pref_ca = models.PreferredCertificateAuthority( - self.project.id, - self.ca_id) - - # data for stored key cases - self.private_key = models.Secret() - self.private_key.secret_type = 'PRIVATE' - self.private_key.project_id = self.project.id - secret_repo.create_from(self.private_key) - - self.public_key = models.Secret() - self.public_key.secret_type = 'PUBLIC' - self.public_key.project_id = self.project.id - secret_repo.create_from(self.public_key) - - self.passphrase = models.Secret() - self.passphrase.secret_type = 'PASSPHRASE' - self.passphrase.project_id = self.project.id - secret_repo.create_from(self.passphrase) - - self.private_key_value = None - self.public_key_value = "public_key" - self.passphrase_value = None - - self.parsed_container_with_passphrase = { - 'name': 'container name', - 'type': 'rsa', - 'secret_refs': [ - {'name': 'private_key', - 'secret_ref': 'https://localhost/secrets/' + - self.private_key.id}, - {'name': 'public_key', - 'secret_ref': 'https://localhost/secrets/' + - self.public_key.id}, - {'name': 'private_key_passphrase', - 'secret_ref': 'https://localhost/secrets/' + - self.passphrase.id} - ] - } - - self.parsed_container = { - 'name': 'container name', - 'type': 'rsa', - 'secret_refs': [ - {'name': 'private_key', - 'secret_ref': 'https://localhost/secrets/' + - self.private_key.id}, - {'name': 'public_key', - 'secret_ref': 'https://localhost/secrets/' + - self.public_key.id} - ] - } - - self.container_with_passphrase = models.Container( - self.parsed_container_with_passphrase) - self.container_with_passphrase.project_id = self.project.id - container_repo.create_from(self.container_with_passphrase) - - self.container = models.Container(self.parsed_container) - self.container.project_id = self.project.id - container_repo.create_from(self.container) - - repositories.commit() - - self.stored_key_meta = { - cert_man.REQUEST_TYPE: - cert_man.CertificateRequestType.STORED_KEY_REQUEST, - "container_ref": - "https://localhost/containers/" + self.container.id, - "subject_dn": "cn=host.example.com,ou=dev,ou=us,o=example.com" - } - - self.order = models.Order() - self.order.meta = self.order_meta - self.order.project_id = self.project.id - self.order.order_barbican_meta = self.barbican_meta - self.order.type = 'certificate' - order_repo.create_from(self.order) - - self._config_cert_plugin() - self._config_store_plugin() - self._config_cert_event_plugin() - self._config_save_meta_plugin() - self._config_get_meta_plugin() - self._config_save_barbican_meta_plugin() - self._config_get_barbican_meta_plugin() - self._config_barbican_meta_dto() - - def tearDown(self): - super(BaseCertificateRequestsTestCase, self).tearDown() - self.cert_plugin_patcher.stop() - self.save_plugin_meta_patcher.stop() - self.get_plugin_meta_patcher.stop() - self.cert_event_plugin_patcher.stop() - self.barbican_meta_dto_patcher.stop() - self.save_barbican_barbican_meta_patcher.stop() - self.get_barbican_plugin_meta_patcher.stop() - self.store_plugin_patcher.stop() - - def stored_key_side_effect(self, *args, **kwargs): - if args[0] == 'PRIVATE': - return secret_store.SecretDTO( - secret_store.SecretType.PRIVATE, - self.private_key_value, - None, - 'application/octet-string', - None) - elif args[0] == 'PASSPHRASE': - return secret_store.SecretDTO( - secret_store.SecretType.PASSPHRASE, - self.passphrase_value, - None, - 'application/octet-string', - None) - elif args[0] == 'PUBLIC': - return secret_store.SecretDTO( - secret_store.SecretType.PUBLIC, - self.public_key_value, - None, - 'application/octet-string', - None) - else: - return None - - def _test_should_return_waiting_for_ca(self, method_to_test): - self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA - - method_to_test( - self.order, self.project, self.result_follow_on) - - self.assertEqual( - common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK, - self.result_follow_on.retry_task) - self.assertEqual( - cert_res.ORDER_STATUS_REQUEST_PENDING.id, - self.result_follow_on.status) - self.assertEqual( - cert_res.ORDER_STATUS_REQUEST_PENDING.message, - self.result_follow_on.status_message) - - def _test_should_return_certificate_generated(self, method_to_test): - self.result.status = cert_man.CertificateStatus.CERTIFICATE_GENERATED - - method_to_test( - self.order, self.project, self.result_follow_on) - - self.assertEqual( - common.RetryTasks.NO_ACTION_REQUIRED, - self.result_follow_on.retry_task) - self.assertEqual( - cert_res.ORDER_STATUS_CERT_GENERATED.id, - self.result_follow_on.status) - self.assertEqual( - cert_res.ORDER_STATUS_CERT_GENERATED.message, - self.result_follow_on.status_message) - - def _test_should_raise_client_data_issue_seen(self, method_to_test): - self.result.status = cert_man.CertificateStatus.CLIENT_DATA_ISSUE_SEEN - - self.assertRaises( - cert_man.CertificateStatusClientDataIssue, - method_to_test, - self.order, - self.project, - self.result_follow_on - ) - - def _test_should_raise_status_not_supported(self, method_to_test): - self.result.status = "Legend of Link" - - self.assertRaises( - cert_man.CertificateStatusNotSupported, - method_to_test, - self.order, - self.project, - self.result_follow_on - ) - - def _config_cert_plugin(self): - """Mock the certificate plugin manager.""" - cert_plugin_config = { - 'return_value.get_plugin.return_value': self.cert_plugin, - 'return_value.get_plugin_by_name.return_value': self.cert_plugin, - 'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin - } - self.cert_plugin_patcher = mock.patch( - 'barbican.plugin.interface.certificate_manager' - '.CertificatePluginManager', - **cert_plugin_config - ) - self.cert_plugin_patcher.start() - - def _config_store_plugin(self): - """Mock the secret store plugin manager.""" - store_plugin_config = { - 'return_value.get_plugin_retrieve_delete.return_value': - self.store_plugin - } - self.store_plugin_patcher = mock.patch( - 'barbican.plugin.interface.secret_store' - '.get_manager', - **store_plugin_config - ) - self.store_plugin_patcher.start() - - def _config_cert_event_plugin(self): - """Mock the certificate event plugin manager.""" - self.cert_event_plugin_patcher = mock.patch( - 'barbican.plugin.interface.certificate_manager' - '._EVENT_PLUGIN_MANAGER' - ) - self.cert_event_plugin_patcher.start() - - def _config_save_meta_plugin(self): - """Mock the save plugin meta function.""" - self.save_plugin_meta_patcher = mock.patch( - 'barbican.tasks.certificate_resources._save_plugin_metadata' - ) - self.mock_save_plugin = self.save_plugin_meta_patcher.start() - - def _config_get_meta_plugin(self): - """Mock the get plugin meta function.""" - get_plugin_config = {'return_value': self.plugin_meta} - self.get_plugin_meta_patcher = mock.patch( - 'barbican.tasks.certificate_resources._get_plugin_meta', - **get_plugin_config - ) - self.get_plugin_meta_patcher.start() - - def _config_save_barbican_meta_plugin(self): - """Mock the save barbican plugin meta function.""" - self.save_barbican_barbican_meta_patcher = mock.patch( - 'barbican.tasks.certificate_resources._save_barbican_metadata' - ) - self.mock_barbican_save_plugin = ( - self.save_barbican_barbican_meta_patcher.start() - ) - - def _config_get_barbican_meta_plugin(self): - """Mock the get barbican plugin meta function.""" - get_barbican_plugin_config = {'return_value': self.barbican_meta} - self.get_barbican_plugin_meta_patcher = mock.patch( - 'barbican.tasks.certificate_resources._get_barbican_meta', - **get_barbican_plugin_config - ) - self.get_barbican_plugin_meta_patcher.start() - - def _config_barbican_meta_dto(self): - """Mock the BarbicanMetaDTO.""" - get_plugin_config = {'return_value': self.barbican_meta_dto} - self.barbican_meta_dto_patcher = mock.patch( - 'barbican.plugin.interface.certificate_manager' - '.BarbicanMetaDTO', - **get_plugin_config - ) - self.barbican_meta_dto_patcher.start() - - -class WhenIssuingCertificateRequests(BaseCertificateRequestsTestCase): - """Tests the 'issue_certificate_request()' function.""" - - def tearDown(self): - super(WhenIssuingCertificateRequests, self).tearDown() - - def test_should_return_waiting_for_ca(self): - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - - def test_should_return_waiting_for_ca_as_retry(self): - # For a retry, the plugin-name to look up would have already been - # saved into the barbican metadata for the order, so just make sure - # we can retrieve it. - self.barbican_meta.update({'plugin_name': 'foo-plugin'}) - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - - def test_should_return_certificate_generated(self): - self._test_should_return_certificate_generated( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - - def test_should_raise_client_data_issue_seen(self): - self._test_should_raise_client_data_issue_seen( - cert_res.issue_certificate_request) - - def _do_pyopenssl_stored_key_request(self): - self.order_meta.update(self.stored_key_meta) - - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 2048) - key_pem = crypto.dump_privatekey( - crypto.FILETYPE_PEM, pkey) - self.private_key_value = base64.b64encode(key_pem) - self.public_key_value = "public_key" - self.passphrase_value = None - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - def test_should_return_for_pyopenssl_stored_key(self): - self._do_pyopenssl_stored_key_request() - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta.get('generated_csr')) - - # TODO(alee-3) Add tests to validate the request based on the validator - # code that dave-mccowan is adding. - - def test_should_return_for_openssl_stored_key_ca_id_passed_in(self): - self.stored_key_meta['ca_id'] = self.ca_id2 - self._do_pyopenssl_stored_key_request() - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - def test_should_return_for_openssl_stored_key_pref_ca_defined(self): - preferred_ca_repo.create_from(self.pref_ca) - self._do_pyopenssl_stored_key_request() - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - def test_should_return_for_openssl_stored_key_global_ca_defined(self): - preferred_ca_repo.create_from(self.global_pref_ca) - self._do_pyopenssl_stored_key_request() - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - def test_should_return_for_pyopenssl_stored_key_with_passphrase(self): - self.order_meta.update(self.stored_key_meta) - self.order_meta['container_ref'] = ( - "https://localhost/containers/" + self.container_with_passphrase.id - ) - - passphrase = "my secret passphrase" - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 2048) - key_pem = crypto.dump_privatekey( - crypto.FILETYPE_PEM, - pkey, - passphrase=passphrase.encode('utf-8') - ) - self.private_key_value = base64.b64encode(key_pem) - self.public_key_value = "public_key" - self.passphrase_value = base64.b64encode(passphrase.encode('utf-8')) - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - # TODO(alee-3) Add tests to validate the request based on the validator - # code that dave-mccowan is adding. - - def test_should_return_for_pycrypto_stored_key_with_passphrase(self): - self.order_meta.update(self.stored_key_meta) - self.order_meta['container_ref'] = ( - "https://localhost/containers/" + self.container_with_passphrase.id - ) - passphrase = "my secret passphrase" - - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend() - ) - - public_key = private_key.public_key() - - private_key_pem = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization. - BestAvailableEncryption(encodeutils.safe_encode(passphrase)) - ) - self.private_key_value = base64.b64encode(private_key_pem) - - public_key_pem = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.PKCS1 - ) - self.public_key_value = base64.b64encode(public_key_pem) - - self.passphrase_value = base64.b64encode(passphrase.encode('utf-8')) - - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - # TODO(alee-3) Add tests to validate the request based on the validator - # code that dave-mccowan is adding. - - def test_should_return_for_pycrypto_stored_key_without_passphrase(self): - self.order_meta.update(self.stored_key_meta) - - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend() - ) - - public_key = private_key.public_key() - - private_key_pem = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption() - ) - self.private_key_value = base64.b64encode(private_key_pem) - - public_key_pem = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.PKCS1 - ) - self.public_key_value = base64.b64encode(public_key_pem) - - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta['generated_csr']) - - # TODO(alee-3) Add tests to validate the request based on the validator - # code that dave-mccowan is adding. - - def test_should_raise_for_pycrypto_stored_key_no_container(self): - self.order_meta.update(self.stored_key_meta) - - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend() - ) - - public_key = private_key.public_key() - - private_key_pem = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption() - ) - self.private_key_value = base64.b64encode(private_key_pem) - - public_key_pem = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.PKCS1 - ) - self.public_key_value = base64.b64encode(public_key_pem) - - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA - container_repo.delete_project_entities(self.project.id) - - self.assertRaises(excep.StoredKeyContainerNotFound, - cert_res.issue_certificate_request, - self.order, - self.project, - self.result_follow_on) - - def test_should_raise_for_pycrypto_stored_key_no_private_key(self): - private_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend() - ) - - public_key = private_key.public_key() - - private_key_pem = private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.NoEncryption() - ) - self.private_key_value = base64.b64encode(private_key_pem) - - public_key_pem = public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.PKCS1 - ) - self.public_key_value = base64.b64encode(public_key_pem) - - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA - - secret_repo.delete_entity_by_id( - self.private_key.id, self.external_project_id) - - # We need to commit deletions or we'll get deleted objects with deleted - # set to True. This is caused by SQLAlchemy's identity mapping and our - # use of scoped_session. - repositories.commit() - self.order.meta.update(self.stored_key_meta) - self.assertRaises(excep.StoredKeyPrivateKeyNotFound, - cert_res.issue_certificate_request, - self.order, - self.project, - self.result_follow_on) - - def test_should_return_for_pyopenssl_stored_key_with_extensions(self): - self.order_meta.update(self.stored_key_meta) - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 2048) - self.private_key_value = base64.b64encode(crypto.dump_privatekey( - crypto.FILETYPE_PEM, pkey)) - - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - self.order_meta['extensions'] = 'my ASN.1 extensions structure here' - # TODO(alee-3) Add real extensions data here - - self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA - - cert_res.issue_certificate_request(self.order, - self.project, - self.result_follow_on) - - self._verify_issue_certificate_plugins_called() - self.assertIsNotNone(self.order.order_barbican_meta['generated_csr']) - - # TODO(alee-3) Add tests to validate the request based on the validator - # code that dave-mccowan is adding. - # TODO(alee-3) Add tests to validate the extensions in the request - - def test_should_raise_invalid_operation_seen(self): - self.result.status = cert_man.CertificateStatus.INVALID_OPERATION - - self.assertRaises( - cert_man.CertificateStatusInvalidOperation, - cert_res.issue_certificate_request, - self.order, - self.project, - self.result_follow_on - ) - - def test_should_return_ca_unavailable_for_request(self): - retry_msec = 123 - status_msg = 'Test status' - self.result.status = ( - cert_man.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST) - self.result.retry_msec = retry_msec - self.result.status_message = status_msg - order_ref = hrefs.convert_order_to_href(self.order.id) - - cert_res.issue_certificate_request(self.order, - self.project, - self.result_follow_on) - - self._verify_issue_certificate_plugins_called() - - epm = self.cert_event_plugin_patcher.target._EVENT_PLUGIN_MANAGER - epm.notify_ca_is_unavailable.assert_called_once_with( - self.project.id, - order_ref, - status_msg, - retry_msec - ) - self._verify_issue_certificate_plugins_called() - self.assertEqual( - common.RetryTasks.INVOKE_SAME_TASK, - self.result_follow_on.retry_task) - self.assertEqual( - cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.id, - self.result_follow_on.status) - self.assertEqual( - cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.message, - self.result_follow_on.status_message) - - def test_should_raise_status_not_supported(self): - self._test_should_raise_status_not_supported( - cert_res.issue_certificate_request) - - def _verify_issue_certificate_plugins_called(self): - self.cert_plugin.issue_certificate_request.assert_called_once_with( - self.order.id, - self.order_meta, - self.plugin_meta, - self.barbican_meta_dto - ) - - self.mock_save_plugin.assert_called_once_with( - self.order, - self.plugin_meta - ) - - self.mock_barbican_save_plugin.assert_called_once_with( - self.order, - self.barbican_meta - ) - - -class WhenCheckingCertificateRequests(BaseCertificateRequestsTestCase): - """Tests the 'check_certificate_request()' function.""" - - def setUp(self): - super(WhenCheckingCertificateRequests, self).setUp() - - def tearDown(self): - super(WhenCheckingCertificateRequests, self).tearDown() - - def test_should_return_waiting_for_ca(self): - self._test_should_return_waiting_for_ca( - cert_res.check_certificate_request) - - self._verify_check_certificate_plugins_called() - - def test_should_return_certificate_generated(self): - self._test_should_return_certificate_generated( - cert_res.check_certificate_request) - - self._verify_check_certificate_plugins_called() - - def test_should_raise_client_data_issue_seen(self): - self._test_should_raise_client_data_issue_seen( - cert_res.check_certificate_request) - - def test_should_raise_status_not_supported(self): - self._test_should_raise_status_not_supported( - cert_res.check_certificate_request) - - def test_should_return_ca_unavailable_for_request(self): - retry_msec = 123 - status_msg = 'Test status' - self.result.status = ( - cert_man.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST) - self.result.retry_msec = retry_msec - self.result.status_message = status_msg - order_ref = hrefs.convert_order_to_href(self.order.id) - - cert_res.check_certificate_request(self.order, - self.project, - self.result_follow_on) - - self._verify_check_certificate_plugins_called() - - epm = self.cert_event_plugin_patcher.target._EVENT_PLUGIN_MANAGER - epm.notify_ca_is_unavailable.assert_called_once_with( - self.project.id, - order_ref, - status_msg, - retry_msec - ) - self.assertEqual( - common.RetryTasks.INVOKE_SAME_TASK, - self.result_follow_on.retry_task) - self.assertEqual( - cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.id, - self.result_follow_on.status) - self.assertEqual( - cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.message, - self.result_follow_on.status_message) - - def _do_pyopenssl_stored_key_request(self): - self.order_meta.update(self.stored_key_meta) - - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 2048) - key_pem = crypto.dump_privatekey( - crypto.FILETYPE_PEM, pkey) - self.private_key_value = base64.b64encode(key_pem) - self.public_key_value = "public_key" - self.passphrase_value = None - self.store_plugin.get_secret.side_effect = self.stored_key_side_effect - - self._test_should_return_waiting_for_ca( - cert_res.issue_certificate_request) - - self._test_should_return_certificate_generated( - cert_res.check_certificate_request) - - def test_should_return_for_pyopenssl_stored_key(self): - self._do_pyopenssl_stored_key_request() - self._verify_check_certificate_plugins_called() - self.assertIsNotNone( - self.order.order_barbican_meta.get('generated_csr')) - - def _verify_check_certificate_plugins_called(self): - self.cert_plugin.check_certificate_status.assert_called_once_with( - self.order.id, - self.order_meta, - self.plugin_meta, - self.barbican_meta_dto - ) - - self.mock_save_plugin.assert_called_with( - self.order, - self.plugin_meta - ) - - -class WhenCreatingSubordinateCAs(database_utils.RepositoryTestCase): - """Tests the 'create_subordinate_ca()' function.""" - - def setUp(self): - super(WhenCreatingSubordinateCAs, self).setUp() - self.project = res.get_or_create_project('12345') - self.project2 = res.get_or_create_project('56789') - - self.subject_name = "cn=subca1 signing certificate, o=example.com" - self.creator_id = "user12345" - self.name = "Subordinate CA #1" - self.description = "This is a test subordinate CA" - self.plugin_name = "dogtag_plugin" - - # create parent ca - expiration = (datetime.datetime.utcnow() + - datetime.timedelta(minutes=10)) - parsed_ca = {'plugin_name': self.plugin_name, - 'plugin_ca_id': 'ca_master', - 'expiration': expiration.isoformat(), - 'name': 'Dogtag CA', - 'description': 'Master CA for Dogtag plugin', - 'ca_signing_certificate': 'XXXXX', - 'intermediates': 'YYYYY'} - - self.parent_ca = models.CertificateAuthority(parsed_ca) - ca_repo.create_from(self.parent_ca) - self.parent_ca_ref = 'https://localhost:6311/cas/' + self.parent_ca.id - - self.new_ca_dict = { - 'plugin_ca_id': 'ca_subordinate', - 'expiration': expiration.isoformat(), - 'name': 'Dogtag Subordinate CA', - 'description': 'Subordinate CA for Dogtag plugin', - 'ca_signing_certificate': 'XXXXX', - 'intermediates': 'YYYYY', - } - - # mock plugin and calls to plugin - self.cert_plugin = mock.MagicMock() - self.cert_plugin.supports_create_ca.return_value = True - self.cert_plugin.create_ca.return_value = self.new_ca_dict - self._config_cert_plugin() - - def tearDown(self): - super(WhenCreatingSubordinateCAs, self).tearDown() - self.cert_plugin_patcher.stop() - - def test_should_create_subordinate_ca(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - self.assertIsInstance(subca, models.CertificateAuthority) - self.assertEqual(self.project.id, subca.project_id) - self.assertEqual(self.creator_id, subca.creator_id) - self.assertEqual(self.plugin_name, subca.plugin_name) - - def test_should_raise_invalid_parent_ca(self): - self.parent_ca_ref = 'https://localhost:6311/cas/' + "BAD-CA-REF" - self.assertRaises( - excep.InvalidParentCA, - cert_res.create_subordinate_ca, - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - - def test_should_raise_unauthorized_parent_ca(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project2, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - subca_ref = hrefs.convert_certificate_authority_to_href(subca.id) - self.assertRaises( - excep.UnauthorizedSubCA, - cert_res.create_subordinate_ca, - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=subca_ref, - creator_id=self.creator_id) - - def test_should_raise_subcas_not_supported(self): - self.cert_plugin.supports_create_ca.return_value = False - self.assertRaises( - excep.SubCAsNotSupported, - cert_res.create_subordinate_ca, - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - - def test_should_raise_subcas_not_created(self): - self.cert_plugin.create_ca.return_value = None - self.assertRaises( - excep.SubCANotCreated, - cert_res.create_subordinate_ca, - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - - def test_should_delete_subca(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - self.assertIsInstance(subca, models.CertificateAuthority) - cert_res.delete_subordinate_ca(self.project.external_id, subca) - self.cert_plugin.delete_ca.assert_called_once_with(subca.plugin_ca_id) - - def test_should_delete_subca_and_all_related_db_entities(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - project_ca = models.ProjectCertificateAuthority( - self.project.id, - subca.id - ) - project_ca_repo.create_from(project_ca) - preferred_ca = models.PreferredCertificateAuthority( - self.project.id, - subca.id) - preferred_ca_repo.create_from(preferred_ca) - cert_res.delete_subordinate_ca(self.project.external_id, subca) - self.cert_plugin.delete_ca.assert_called_once_with(subca.plugin_ca_id) - - def test_should_raise_when_delete_pref_subca_with_other_project_ca(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - project_ca = models.ProjectCertificateAuthority( - self.project.id, - subca.id - ) - project_ca_repo.create_from(project_ca) - preferred_ca = models.PreferredCertificateAuthority( - self.project.id, - subca.id) - preferred_ca_repo.create_from(preferred_ca) - subca2 = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - project_ca2 = models.ProjectCertificateAuthority( - self.project.id, - subca2.id - ) - project_ca_repo.create_from(project_ca2) - self.assertRaises( - excep.CannotDeletePreferredCA, - cert_res.delete_subordinate_ca, - self.project.external_id, - subca - ) - - def test_should_raise_cannot_delete_base_ca(self): - self.assertRaises( - excep.CannotDeleteBaseCA, - cert_res.delete_subordinate_ca, - self.project.external_id, - self.parent_ca - ) - - def test_should_raise_unauthorized_subca_delete(self): - subca = cert_res.create_subordinate_ca( - project_model=self.project, - name=self.name, - description=self.description, - subject_dn=self.subject_name, - parent_ca_ref=self.parent_ca_ref, - creator_id=self.creator_id - ) - self.assertRaises( - excep.UnauthorizedSubCA, - cert_res.delete_subordinate_ca, - self.project2.external_id, - subca - ) - - def _config_cert_plugin(self): - """Mock the certificate plugin manager.""" - cert_plugin_config = { - 'return_value.get_plugin.return_value': self.cert_plugin, - 'return_value.get_plugin_by_name.return_value': self.cert_plugin, - 'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin - } - self.cert_plugin_patcher = mock.patch( - 'barbican.plugin.interface.certificate_manager' - '.CertificatePluginManager', - **cert_plugin_config - ) - self.cert_plugin_patcher.start() diff --git a/barbican/tests/tasks/test_resources.py b/barbican/tests/tasks/test_resources.py index d82242b13..749c20a50 100644 --- a/barbican/tests/tasks/test_resources.py +++ b/barbican/tests/tasks/test_resources.py @@ -254,110 +254,6 @@ class WhenBeginningKeyTypeOrder(BaseOrderTestCase): self.order_repo.save.assert_called_once_with(self.order) -class WhenBeginningCertificateTypeOrder(BaseOrderTestCase): - - def setUp(self): - super(WhenBeginningCertificateTypeOrder, self).setUp() - - self.order.type = models.OrderType.CERTIFICATE - self.resource = resources.BeginTypeOrder() - - @mock.patch( - 'barbican.tasks.certificate_resources.issue_certificate_request') - def test_should_process_order_no_container( - self, mock_issue_cert_request): - mock_issue_cert_request.return_value = None - - result = self.resource.process_and_suppress_exceptions( - self.order.id, self.external_project_id) - - self.order_repo.get.assert_called_once_with( - entity_id=self.order.id, - external_project_id=self.external_project_id) - - self.assertEqual(self.order.status, models.States.ACTIVE) - - mock_issue_cert_request.assert_called_once_with( - self.order, - self.project, - mock.ANY - ) - self.assertIsNone(self.order.container_id) - self.assertIsInstance(result, common.FollowOnProcessingStatusDTO) - - @mock.patch( - 'barbican.tasks.certificate_resources.issue_certificate_request') - def test_should_process_order_with_container( - self, mock_issue_cert_request): - mock_issue_cert_request.return_value = self.container - - result = self.resource.process( - self.order.id, self.external_project_id) - - self.order_repo.get.assert_called_once_with( - entity_id=self.order.id, - external_project_id=self.external_project_id) - - self.assertEqual(self.order.status, models.States.ACTIVE) - - mock_issue_cert_request.assert_called_once_with( - self.order, - self.project, - mock.ANY - ) - self.assertEqual(self.container.id, self.order.container_id) - self.assertIsInstance(result, common.FollowOnProcessingStatusDTO) - - -class WhenUpdatingOrder(BaseOrderTestCase): - - def setUp(self): - super(WhenUpdatingOrder, self).setUp() - - self.updated_meta = 'updated' - - self.resource = resources.UpdateOrder() - - @mock.patch( - 'barbican.tasks.certificate_resources.modify_certificate_request') - def test_should_update_certificate_order(self, mock_modify_cert_request): - self.order.type = models.OrderType.CERTIFICATE - - self.resource.process_and_suppress_exceptions( - self.order.id, self.external_project_id, self.updated_meta) - - self.assertEqual(self.order.status, models.States.ACTIVE) - - mock_modify_cert_request.assert_called_once_with( - self.order, - self.updated_meta - ) - - @mock.patch( - 'barbican.tasks.certificate_resources.modify_certificate_request') - def test_should_fail_during_processing(self, mock_mod_cert): - mock_mod_cert.side_effect = ValueError('Abort!') - - self.order.type = models.OrderType.CERTIFICATE - - exception = self.assertRaises( - ValueError, - self.resource.process, - self.order_id, - self.external_project_id, - self.meta - ) - - self.assertEqual('Abort!', str(exception)) - - mock_mod_cert.assert_called_once_with(self.order, self.meta) - - self.assertEqual(models.States.ERROR, self.order.status) - self.assertEqual(500, self.order.error_status_code) - self.assertEqual(u._('Update Order failure seen - please contact ' - 'site administrator.'), self.order.error_reason) - - class WhenBeginningAsymmetricTypeOrder(BaseOrderTestCase): def setUp(self): @@ -457,75 +353,3 @@ class WhenBeginningAsymmetricTypeOrder(BaseOrderTestCase): self.project_repo.get.assert_called_once_with(self.project_id) self.order_repo.save.assert_called_once_with(self.order) - - -class WhenCheckingCertificateStatus(BaseOrderTestCase): - - def setUp(self): - super(WhenCheckingCertificateStatus, self).setUp() - - self.order.type = models.OrderType.CERTIFICATE - - self.resource = resources.CheckCertificateStatusOrder() - - @mock.patch( - 'barbican.tasks.certificate_resources.check_certificate_request') - def test_should_process_order_no_container( - self, mock_check_cert_request): - mock_check_cert_request.return_value = None - - result = self.resource.process_and_suppress_exceptions( - self.order.id, self.external_project_id) - - self.order_repo.get.assert_called_once_with( - entity_id=self.order.id, - external_project_id=self.external_project_id) - - self.assertEqual(self.order.status, models.States.ACTIVE) - - mock_check_cert_request.assert_called_once_with( - self.order, - self.project, - mock.ANY - ) - self.assertIsNone(self.order.container_id) - self.assertIsInstance(result, common.FollowOnProcessingStatusDTO) - - @mock.patch( - 'barbican.tasks.certificate_resources.check_certificate_request') - def test_should_process_order_with_container( - self, mock_check_cert_request): - mock_check_cert_request.return_value = self.container - - self.resource.process(self.order.id, self.external_project_id) - - self.order_repo.get.assert_called_once_with( - entity_id=self.order.id, - external_project_id=self.external_project_id) - - self.assertEqual(self.order.status, models.States.ACTIVE) - - mock_check_cert_request.assert_called_once_with( - self.order, - self.project, - mock.ANY - ) - self.assertEqual(self.container.id, self.order.container_id) - - def test_should_fail_with_bogus_order_type(self): - self.order.type = 'bogus-type' - - self.assertRaises( - NotImplementedError, - self.resource.process, - self.order.id, - self.external_project_id, - ) - - # Order state should be set to ERROR. - self.assertEqual(models.States.ERROR, self.order.status) - self.assertEqual( - ('Check Certificate Order Status failure seen - ' - 'please contact site administrator.'), - self.order.error_reason) - self.assertEqual(500, self.order.error_status_code) diff --git a/devstack/lib/barbican b/devstack/lib/barbican index 2685ef114..8d190aa5f 100644 --- a/devstack/lib/barbican +++ b/devstack/lib/barbican @@ -113,11 +113,7 @@ function configure_dogtag_plugin { iniset $BARBICAN_CONF dogtag_plugin nss_db_path '/etc/barbican/alias' iniset $BARBICAN_CONF dogtag_plugin nss_db_path_ca '/etc/barbican/alias-ca' iniset $BARBICAN_CONF dogtag_plugin nss_password 'password123' - iniset $BARBICAN_CONF dogtag_plugin simple_cmc_profile 'caOtherCert' - iniset $BARBICAN_CONF dogtag_plugin ca_expiration_time 1 - iniset $BARBICAN_CONF dogtag_plugin plugin_working_dir '/etc/barbican/dogtag' iniset $BARBICAN_CONF secretstore enabled_secretstore_plugins dogtag_crypto - iniset $BARBICAN_CONF certificate enabled_certificate_plugins dogtag } # configure_barbican - Set config files, create data dirs, etc diff --git a/etc/oslo-config-generator/barbican.conf b/etc/oslo-config-generator/barbican.conf index 495ba4134..8cb13ae2e 100644 --- a/etc/oslo-config-generator/barbican.conf +++ b/etc/oslo-config-generator/barbican.conf @@ -1,7 +1,5 @@ [DEFAULT] output_file = etc/barbican/barbican.conf.sample -namespace = barbican.certificate.plugin -namespace = barbican.certificate.plugin.snakeoil namespace = barbican.common.config namespace = barbican.plugin.crypto namespace = barbican.plugin.crypto.p11 diff --git a/functionaltests/api/v1/functional/test_quotas_enforce.py b/functionaltests/api/v1/functional/test_quotas_enforce.py index e2b06f81c..21702672e 100644 --- a/functionaltests/api/v1/functional/test_quotas_enforce.py +++ b/functionaltests/api/v1/functional/test_quotas_enforce.py @@ -15,8 +15,6 @@ import testtools -from barbican.plugin.interface import certificate_manager as cert_interface - from functionaltests.api import base from functionaltests.api.v1.behaviors import consumer_behaviors from functionaltests.api.v1.behaviors import container_behaviors @@ -36,11 +34,6 @@ admin_b = CONF.rbac_users.admin_b service_admin = CONF.identity.service_admin -def is_ca_backend_snakeoil(): - return 'snakeoil_ca' in\ - cert_interface.CONF.certificate.enabled_certificate_plugins - - @testtools.testcase.attr('no_parallel') class QuotaEnforcementTestCase(base.TestCase): diff --git a/releasenotes/notes/deprecate-symantec-plugin-c14da58692f8d881.yaml b/releasenotes/notes/deprecate-symantec-plugin-c14da58692f8d881.yaml deleted file mode 100644 index 011df9625..000000000 --- a/releasenotes/notes/deprecate-symantec-plugin-c14da58692f8d881.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - | - The Symantec certificate plugin has been deprecated, because lack of - maintenance activity of the plugin. Also the symantecssl python library - is not generally available and the plugin has never been tested in - upstream. diff --git a/releasenotes/notes/remove-certificate-resources-cdb4708332436144.yaml b/releasenotes/notes/remove-certificate-resources-cdb4708332436144.yaml new file mode 100644 index 000000000..5be2bd31a --- /dev/null +++ b/releasenotes/notes/remove-certificate-resources-cdb4708332436144.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + The certificate plugin and the certificate event plugin were both removed, + because these were used for deprecated certificate resources. diff --git a/setup.cfg b/setup.cfg index ad9424c95..58f486098 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,13 +62,6 @@ barbican.secretstore.plugin = barbican.crypto.plugin = p11_crypto = barbican.plugin.crypto.p11_crypto:P11CryptoPlugin simple_crypto = barbican.plugin.crypto.simple_crypto:SimpleCryptoPlugin -barbican.certificate.plugin = - simple_certificate = barbican.plugin.simple_certificate_manager:SimpleCertificatePlugin - snakeoil_ca = barbican.plugin.snakeoil_ca:SnakeoilCACertificatePlugin - symantec = barbican.plugin.symantec:SymantecCertificatePlugin - dogtag = barbican.plugin.dogtag:DogtagCAPlugin -barbican.certificate.event.plugin = - simple_certificate_event = barbican.plugin.simple_certificate_manager:SimpleCertificateEventPlugin barbican.test.crypto.plugin = test_crypto = barbican.tests.crypto.test_plugin:TestCryptoPlugin oslo.config.opts = @@ -80,7 +73,5 @@ oslo.config.opts = barbican.plugin.crypto.p11 = barbican.plugin.crypto.p11_crypto:list_opts barbican.plugin.secret_store.kmip = barbican.plugin.kmip_secret_store:list_opts barbican.plugin.secret_store.vault = barbican.plugin.vault_secret_store:list_opts - barbican.certificate.plugin = barbican.plugin.interface.certificate_manager:list_opts - barbican.certificate.plugin.snakeoil = barbican.plugin.snakeoil_ca:list_opts oslo.config.opts.defaults = barbican.common.config = barbican.common.config:set_lib_defaults