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:
        barbican_meta_for_plugins_dto.plugin_ca_id = ca_id
        return cert.CertificatePluginManager().get_plugin_by_ca_id(ca_id)
    else:
        return cert.CertificatePluginManager().get_plugin(order_model.meta)
Beispiel #2
0
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 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 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.
    """
    container_model = None
    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)

    # Handle result
    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)
    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=ORDER_STATUS_CA_UNAVAIL_FOR_CHECK,
            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 container_model
def issue_certificate_request(order_model, project_model, repos):
    """Create the initial order with CA.

    :param: order_model - order associated with this cert request
    :param: project_model - project associated with this request
    :param: repos - repos (to be removed)
    :returns: container_model - container with the relevant cert if
        the request has been completed.  None otherwise
    """
    container_model = None

    plugin_meta = _get_plugin_meta(order_model, repos)

    # Locate a suitable plugin to issue a certificate.
    cert_plugin = cert.CertificatePluginManager().get_plugin(order_model.meta)

    request_type = order_model.meta.get(cert.REQUEST_TYPE)
    if request_type == cert.CertificateRequestType.STORED_KEY_REQUEST:
        _generate_csr(order_model, repos)

    result = cert_plugin.issue_certificate_request(order_model.id,
                                                   order_model.meta,
                                                   plugin_meta)

    # Save plugin order plugin state
    _save_plugin_metadata(order_model, plugin_meta, repos)

    # Handle result
    if cert.CertificateStatus.WAITING_FOR_CA == result.status:
        # TODO(alee-3): Add code to set sub status of "waiting for CA"
        _update_order_status(ORDER_STATUS_REQUEST_PENDING)
        _schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
                                     repos, result, project_model,
                                     cert.RETRY_MSEC)
    elif cert.CertificateStatus.CERTIFICATE_GENERATED == result.status:
        _update_order_status(ORDER_STATUS_CERT_GENERATED)
        container_model = _save_secrets(result, project_model, repos)
    elif cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN == result.status:
        _update_order_status(ORDER_STATUS_DATA_INVALID)
        raise cert.CertificateStatusClientDataIssue(result.status_message)
    elif cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST == result.status:
        # TODO(alee-3): set retry counter and error out if retries are exceeded
        _update_order_status(ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE)

        _schedule_issue_cert_request(cert_plugin, order_model, plugin_meta,
                                     repos, result, project_model,
                                     cert.ERROR_RETRY_MSEC)
        _notify_ca_unavailable(order_model, result)
    elif cert.CertificateStatus.INVALID_OPERATION == result.status:
        _update_order_status(ORDER_STATUS_INVALID_OPERATION)

        raise cert.CertificateStatusInvalidOperation(result.status_message)
    else:
        _update_order_status(ORDER_STATUS_INTERNAL_ERROR)
        raise cert.CertificateStatusNotSupported(result.status)

    return container_model
    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 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)
Beispiel #8
0
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 check_certificate_request(order_model, project_model, plugin_name, repos):
    """Check the status of a certificate request with the CA.

    :param: order_model - order associated with this cert request
    :param: project_model - project associated with this request
    :param: plugin_name - plugin the issued the certificate request
    :param; repos - repos (to be removed)
    :returns: container_model - container with the relevant cert if the
        request has been completed.  None otherwise.
    """
    container_model = None
    plugin_meta = _get_plugin_meta(order_model, repos)

    cert_plugin = cert.CertificatePluginManager().get_plugin_by_name(
        plugin_name)

    result = cert_plugin.check_certificate_request(order_model.id,
                                                   order_model.meta,
                                                   plugin_meta)

    # Save plugin order plugin state
    _save_plugin_metadata(order_model, plugin_meta, repos)

    # Handle result
    if cert.CertificateStatus.WAITING_FOR_CA == result.status:
        _update_order_status(ORDER_STATUS_REQUEST_PENDING)
        _schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
                                     repos, result, project_model,
                                     cert.RETRY_MSEC)
    elif cert.CertificateStatus.CERTIFICATE_GENERATED == result.status:
        _update_order_status(ORDER_STATUS_CERT_GENERATED)
        container_model = _save_secrets(result, project_model, repos)
    elif cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN == result.status:
        _update_order_status(cert.ORDER_STATUS_DATA_INVALID)
        raise cert.CertificateStatusClientDataIssue(result.status_message)
    elif cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST == result.status:
        # TODO(alee-3): decide what to do about retries here
        _update_order_status(ORDER_STATUS_CA_UNAVAIL_FOR_CHECK)
        _schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
                                     repos, result, project_model,
                                     cert.ERROR_RETRY_MSEC)

    elif cert.CertificateStatus.INVALID_OPERATION == result.status:
        _update_order_status(ORDER_STATUS_INVALID_OPERATION)
        raise cert.CertificateStatusInvalidOperation(result.status_message)
    else:
        _update_order_status(ORDER_STATUS_INTERNAL_ERROR)
        raise cert.CertificateStatusNotSupported(result.status)

    return container_model
Beispiel #10
0
    def setUp(self):
        super(WhenTestingCertificatePluginManager, self).setUp()
        self.cert_spec = {}

        self.plugin_returned = mock.MagicMock()
        self.plugin_name = 'mock.MagicMock'
        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)
        self.manager = cm.CertificatePluginManager()
        self.manager.extensions = [self.plugin_loaded]
Beispiel #11
0
 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 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
    """
    container_model = None

    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()

    # Locate the required certificate plugin.
    cert_plugin_name = barbican_meta.get('plugin_name')
    if cert_plugin_name:
        cert_plugin = cert.CertificatePluginManager().get_plugin_by_name(
            cert_plugin_name)
    else:
        ca_id = _get_ca_id(order_model.meta, project_model.id)
        if ca_id:
            barbican_meta_for_plugins_dto.plugin_ca_id = ca_id
            cert_plugin = cert.CertificatePluginManager().get_plugin_by_ca_id(
                ca_id)
        else:
            cert_plugin = cert.CertificatePluginManager().get_plugin(
                order_model.meta)
    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(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
    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)
    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=ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE,
            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 container_model
Beispiel #13
0
def refresh_certificate_resources():
    # Before CA operations can be performed, the CA table must be populated
    cert.CertificatePluginManager().refresh_ca_table()