Beispiel #1
0
def test_send_reissue_no_endpoints_notification(notification_plugin, endpoint,
                                                certificate):
    from lemur.notifications.messaging import send_reissue_no_endpoints_notification
    verify_sender_email()

    new_cert = CertificateFactory()
    new_cert.replaces.append(certificate)
    assert send_reissue_no_endpoints_notification(certificate, new_cert)
    certificate.endpoints.append(endpoint)
    assert not send_reissue_no_endpoints_notification(certificate, new_cert)
Beispiel #2
0
def test_send_reissue_no_endpoints_notification_excluded_destination(
        destination_plugin, notification_plugin, certificate, destination):
    from lemur.notifications.messaging import send_reissue_no_endpoints_notification
    verify_sender_email()

    new_cert = CertificateFactory()
    new_cert.replaces.append(certificate)
    destination.label = 'not-excluded-destination'
    certificate.destinations.append(destination)
    assert send_reissue_no_endpoints_notification(certificate, new_cert)
    # specified in tests/conf.py
    destination.label = 'excluded-destination'
    assert not send_reissue_no_endpoints_notification(certificate, new_cert)
Beispiel #3
0
def request_reissue(certificate, notify, commit):
    """
    Reissuing certificate and handles any exceptions.
    :param certificate:
    :param notify:
    :param commit:
    :return:
    """
    status = FAILURE_METRIC_STATUS
    notify = notify and certificate.notify
    try:
        print("[+] {0} is eligible for re-issuance".format(certificate.name))

        # set the lemur identity for all cli commands
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(1))

        details = get_certificate_primitives(certificate)
        print_certificate_details(details)

        if commit:
            new_cert = reissue_certificate(certificate,
                                           notify=notify,
                                           replace=True)
            print("[+] New certificate named: {0}".format(new_cert.name))
            if notify and isinstance(
                    new_cert,
                    Certificate):  # let celery handle PendingCertificates
                send_reissue_no_endpoints_notification(certificate, new_cert)

        status = SUCCESS_METRIC_STATUS

    except Exception as e:
        capture_exception(extra={"certificate_name": str(certificate.name)})
        current_app.logger.exception(
            f"Error reissuing certificate: {certificate.name}", exc_info=True)
        print(
            f"[!] Failed to reissue certificate: {certificate.name}. Reason: {e}"
        )
        if notify:
            send_reissue_failed_notification(certificate)

    metrics.send(
        "certificate_reissue",
        "counter",
        1,
        metric_tags={
            "status": status,
            "certificate": certificate.name
        },
    )
Beispiel #4
0
def test_send_reissue_no_endpoints_notification(certificate):
    from lemur.notifications.messaging import send_reissue_no_endpoints_notification

    verify_sender_email()
    new_certificate = CertificateFactory()
    new_certificate.replaces.append(certificate)
    verify_sender_email()
    assert send_reissue_no_endpoints_notification(certificate, new_certificate)
Beispiel #5
0
def fetch_acme_cert(id, notify_reissue_cert_id=None):
    """
    Attempt to get the full certificate for the pending certificate listed.

    Args:
        id: an id of a PendingCertificate
        notify_reissue_cert_id: ID of existing Certificate to use for reissue notifications, if supplied
    """
    task_id = None
    if celery.current_task:
        task_id = celery.current_task.request.id

    function = f"{__name__}.{sys._getframe().f_code.co_name}"
    log_data = {
        "function": function,
        "message": "Resolving pending certificate {}".format(id),
        "task_id": task_id,
        "id": id,
    }

    current_app.logger.debug(log_data)

    if task_id and is_task_active(log_data["function"], task_id, (id, )):
        log_data["message"] = "Skipping task: Task is already active"
        current_app.logger.debug(log_data)
        return

    pending_certs = pending_certificate_service.get_pending_certs([id])
    new = 0
    failed = 0
    wrong_issuer = 0
    acme_certs = []

    # We only care about certs using the acme-issuer plugin
    for cert in pending_certs:
        cert_authority = get_authority(cert.authority_id)
        if cert_authority.plugin_name == "acme-issuer":
            acme_certs.append(cert)
        else:
            wrong_issuer += 1

    authority = plugins.get("acme-issuer")
    resolved_certs = authority.get_ordered_certificates(acme_certs)

    for cert in resolved_certs:
        real_cert = cert.get("cert")
        # It's necessary to reload the pending cert due to detached instance: http://sqlalche.me/e/bhk3
        pending_cert = pending_certificate_service.get(
            cert.get("pending_cert").id)
        if not pending_cert or pending_cert.resolved:
            # pending_cert is cleared or it was resolved by another process
            log_data[
                "message"] = "Pending certificate doesn't exist anymore. Was it resolved by another process?"
            current_app.logger.error(log_data)
            continue
        if real_cert:
            # If a real certificate was returned from issuer, then create it in Lemur and mark
            # the pending certificate as resolved
            final_cert = pending_certificate_service.create_certificate(
                pending_cert, real_cert, pending_cert.user)
            pending_certificate_service.update(cert.get("pending_cert").id,
                                               resolved_cert_id=final_cert.id)
            pending_certificate_service.update(cert.get("pending_cert").id,
                                               resolved=True)
            if notify_reissue_cert_id is not None:
                notify_reissue_cert = certificate_service.get(
                    notify_reissue_cert_id)
                send_reissue_no_endpoints_notification(notify_reissue_cert,
                                                       final_cert)
            # add metrics to metrics extension
            new += 1
        else:
            failed += 1
            error_log = copy.deepcopy(log_data)
            error_log["message"] = "Pending certificate creation failure"
            error_log["pending_cert_id"] = pending_cert.id
            error_log["last_error"] = cert.get("last_error")
            error_log["cn"] = pending_cert.cn

            if pending_cert.number_attempts > ACME_ADDITIONAL_ATTEMPTS:
                error_log["message"] = "Deleting pending certificate"
                send_pending_failure_notification(
                    pending_cert, notify_owner=pending_cert.notify)
                if notify_reissue_cert_id is not None:
                    send_reissue_failed_notification(pending_cert)
                # Mark the pending cert as resolved
                pending_certificate_service.update(cert.get("pending_cert").id,
                                                   resolved=True)
            else:
                pending_certificate_service.increment_attempt(pending_cert)
                pending_certificate_service.update(cert.get("pending_cert").id,
                                                   status=str(
                                                       cert.get("last_error")))
                # Add failed pending cert task back to queue
                fetch_acme_cert.delay(id, notify_reissue_cert_id)
            current_app.logger.error(error_log)
    log_data["message"] = "Complete"
    log_data["new"] = new
    log_data["failed"] = failed
    log_data["wrong_issuer"] = wrong_issuer
    current_app.logger.debug(log_data)
    metrics.send(f"{function}.resolved", "gauge", new)
    metrics.send(f"{function}.failed", "gauge", failed)
    metrics.send(f"{function}.wrong_issuer", "gauge", wrong_issuer)
    print(
        "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}"
        .format(new=new, failed=failed, wrong_issuer=wrong_issuer))
    return log_data