Esempio n. 1
0
def fetch_all_pending_acme_certs():
    """Instantiate celery workers to resolve all pending Acme certificates"""
    pending_certs = pending_certificate_service.get_unresolved_pending_certs()

    function = f"{__name__}.{sys._getframe().f_code.co_name}"
    log_data = {
        "function": function,
        "message": "Starting job.",
    }

    current_app.logger.debug(log_data)

    # 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":
            if datetime.now(timezone.utc) - cert.last_updated > timedelta(
                    minutes=5):
                log_data["message"] = "Triggering job for cert {}".format(
                    cert.name)
                log_data["cert_name"] = cert.name
                log_data["cert_id"] = cert.id
                current_app.logger.debug(log_data)
                fetch_acme_cert.delay(cert.id)

    red.set(f'{function}.last_success', int(time.time()))
    metrics.send(f"{function}.success", 'counter', 1)
Esempio n. 2
0
def fetch_all_pending_acme_certs():
    """Instantiate celery workers to resolve all pending Acme certificates"""

    function = f"{__name__}.{sys._getframe().f_code.co_name}"
    task_id = None
    if celery.current_task:
        task_id = celery.current_task.request.id

    log_data = {
        "function": function,
        "message": "Starting job.",
        "task_id": task_id,
    }

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

    current_app.logger.debug(log_data)
    pending_certs = pending_certificate_service.get_unresolved_pending_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":
            if datetime.now(timezone.utc) - cert.last_updated > timedelta(minutes=5):
                log_data["message"] = "Triggering job for cert {}".format(cert.name)
                log_data["cert_name"] = cert.name
                log_data["cert_id"] = cert.id
                current_app.logger.debug(log_data)
                fetch_acme_cert.delay(cert.id)

    metrics.send(f"{function}.success", "counter", 1)
    return log_data
Esempio n. 3
0
def fetch_all_pending_acme_certs():
    """Instantiate celery workers to resolve all pending Acme certificates"""
    pending_certs = pending_certificate_service.get_unresolved_pending_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':
            if cert.last_updated == cert.date_created or datetime.now(
                    timezone.utc) - cert.last_updated > timedelta(minutes=3):
                fetch_acme_cert.delay(cert.id)
Esempio n. 4
0
    def revoke_certificate(self, certificate, comments):
        """Revoke an EJBCA certificate."""
        base_url = current_app.config.get("EJBCA_URL")

        authority = get_authority(certificate.authority_id)
        authority_const = authority.name.upper().replace('-', '_')

        cert_body = certificate.body

        x509 = load_certificate(FILETYPE_PEM, cert_body)

        issuer = x509.get_issuer()
        issuer_dn = get_subject_dn_string(issuer.get_components())

        # create certificate revocation request
        hex_serial = hex(int(certificate.serial))[2:]

        cert_serial_hex = str(hex_serial)

        create_url = "{0}/ejbca/ejbca-rest-api/v1/certificate/{1}/{2}/revoke".format(
            base_url, issuer_dn, cert_serial_hex)

        # print(create_url)
        session = requests.Session()
        session.mount('https://', HttpsAdapter())
        session.cert = current_app.config.get(
            f'EJBCA_PEM_PATH_{authority_const}')

        session.verify = current_app.config.get("EJBCA_TRUSTSTORE")
        session.hooks = dict(response=log_status_code)

        metrics.send("ejbca_revoke_certificate", "counter", 1)
        reason = comments.get('crl_reason') or comments.get(
            'crlReason', 'unspecified')

        reason_dict = {
            'unspecified': 'UNSPECIFIED',
            'keyCompromise': 'KEY_COMPROMISE',
            'cACompromise': 'CA_COMPROMISE',
            'affiliationChanged': 'AFFILIATION_CHANGED',
            'superseded': 'SUPERSEDED',
            'cessationOfOperation': 'CESSATION_OF_OPERATION',
            'certificateHold': 'CERTIFICATE_HOLD',
            'removeFromCRL': 'REMOVE_FROM_CRL',
            'privilegeWithdrawn': 'PRIVILEGES_WITHDRAWN',
            'aACompromise': 'AA_COMPROMISE',
        }
        reason = reason_dict.get(reason, reason)
        response = session.put(create_url, params={'reason': reason})
        # print(response)
        extra_logger.info(f'{certificate} was revoked with reason {reason}')
        return handle_response(response)
Esempio n. 5
0
def fetch_all_acme():
    """
    Attempt to get full certificates for each pending certificate listed with the acme-issuer. This is more efficient
    for acme-issued certificates because it will configure all of the DNS challenges prior to resolving any
    certificates.
    """
    pending_certs = pending_certificate_service.get_pending_certs('all')
    user = user_service.get_by_username('lemur')
    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 real_cert:
            # If a real certificate was returned from issuer, then create it in Lemur and delete
            # the pending certificate
            pending_certificate_service.create_certificate(
                pending_cert, real_cert, user)
            pending_certificate_service.delete_by_id(pending_cert.id)
            # add metrics to metrics extension
            new += 1
        else:
            pending_certificate_service.increment_attempt(pending_cert)
            failed += 1
    print(
        "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}"
        .format(new=new, failed=failed, wrong_issuer=wrong_issuer))
Esempio n. 6
0
def fetch_all_pending_acme_certs():
    """Instantiate celery workers to resolve all pending Acme certificates"""
    pending_certs = pending_certificate_service.get_unresolved_pending_certs()

    log_data = {
        "function": "{}.{}".format(__name__, sys._getframe().f_code.co_name),
        "message": "Starting job."
    }

    current_app.logger.debug(log_data)

    # 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':
            if datetime.now(timezone.utc) - cert.last_updated > timedelta(minutes=5):
                log_data["message"] = "Triggering job for cert {}".format(cert.name)
                log_data["cert_name"] = cert.name
                log_data["cert_id"] = cert.id
                current_app.logger.debug(log_data)
                fetch_acme_cert.delay(cert.id)
Esempio n. 7
0
def fetch_all_pending_acme_certs():
    """Instantiate celery workers to resolve all pending Acme certificates"""
    pending_certs = pending_certificate_service.get_unresolved_pending_certs()

    log_data = {
        "function": "{}.{}".format(__name__, sys._getframe().f_code.co_name),
        "message": "Starting job."
    }

    current_app.logger.debug(log_data)

    # 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':
            if datetime.now(timezone.utc) - cert.last_updated > timedelta(minutes=5):
                log_data["message"] = "Triggering job for cert {}".format(cert.name)
                log_data["cert_name"] = cert.name
                log_data["cert_id"] = cert.id
                current_app.logger.debug(log_data)
                fetch_acme_cert.delay(cert.id)
Esempio n. 8
0
def fetch_all_pending_certs():
    """Instantiate celery workers to resolve all certificates"""

    function = f"{__name__}.{sys._getframe().f_code.co_name}"
    task_id = None
    if celery.current_task:
        task_id = celery.current_task.request.id

    log_data = {
        "function": function,
        "message": "Starting fetching all pending certs.",
        "task_id": task_id,
    }

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

    current_app.logger.debug(log_data)
    pending_certs = pending_certificate_service.get_unresolved_pending_certs()

    for cert in pending_certs:
        cert_authority = get_authority(cert.authority_id)
        # handle only certs from non-acme issuers, as acme certs are specially
        #  taken care of in the `fetach_all_pending_acme_certs` function
        if cert_authority.plugin_name != "acme-issuer":
            log_data["message"] = "Triggering job for cert {}".format(
                cert.name)
            log_data["cert_name"] = cert.name
            log_data["cert_id"] = cert.id
            current_app.logger.debug(log_data)
            fetch_cert.delay(cert.id)

    metrics.send(f"{function}.success", "counter", 1)
    return log_data
Esempio n. 9
0
def fetch_acme_cert(id):
    """
    Attempt to get the full certificate for the pending certificate listed.

    Args:
        id: an id of a PendingCertificate
    """
    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)
            # 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)
                # 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)
            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
Esempio n. 10
0
def fetch_acme_cert(id):
    """
    Attempt to get the full certificate for the pending certificate listed.

    Args:
        id: an id of a PendingCertificate
    """
    log_data = {
        "function": "{}.{}".format(__name__, sys._getframe().f_code.co_name),
        "message": "Resolving pending certificate {}".format(id)
    }
    current_app.logger.debug(log_data)
    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:
            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=True
            )
            pending_certificate_service.update(
                cert.get("pending_cert").id,
                resolved_cert_id=final_cert.id
            )
            # 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 > 4:
                error_log["message"] = "Deleting pending certificate"
                send_pending_failure_notification(pending_cert, notify_owner=pending_cert.notify)
                # 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)
            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)
    print(
        "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}".format(
            new=new,
            failed=failed,
            wrong_issuer=wrong_issuer
        )
    )
Esempio n. 11
0
File: cli.py Progetto: x-lhan/lemur
def fetch_all_acme():
    """
    Attempt to get full certificates for each pending certificate listed with the acme-issuer. This is more efficient
    for acme-issued certificates because it will configure all of the DNS challenges prior to resolving any
    certificates.
    """

    log_data = {
        "function": "{}.{}".format(__name__, sys._getframe().f_code.co_name)
    }
    pending_certs = pending_certificate_service.get_unresolved_pending_certs()
    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 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(
                pending_cert.id,
                resolved=True
            )
            pending_certificate_service.update(
                pending_cert.id,
                resolved_cert_id=final_cert.id
            )
            # 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 > 4:
                error_log["message"] = "Marking pending certificate as resolved"
                send_pending_failure_notification(pending_cert, notify_owner=pending_cert.notify)
                # Mark "resolved" as True
                pending_certificate_service.update(
                    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"))
                )
            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)
    print(
        "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}".format(
            new=new,
            failed=failed,
            wrong_issuer=wrong_issuer
        )
    )
Esempio n. 12
0
def fetch_cert(id):
    """
    Attempt to get the full certificate for the pending certificate listed.

    Args:
        id: an id of a PendingCertificate
    """
    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
    for cert in pending_certs:
        cert_authority = get_authority(cert.authority_id)
        if cert_authority.plugin_name == "acme-issuer":
            current_app.logger.warning(
                "Skipping acme cert (use `fetch_acme_cert()` instead).")
            continue
        plugin = plugins.get(cert_authority.plugin_name)
        real_cert = plugin.get_ordered_certificate(cert)
        if real_cert:
            # If a real certificate was returned from issuer, then create it in
            # Lemur and mark the pending certificate as resolved
            # Ideally, this should be a db transaction that would check resolved status
            # before creating a new one
            final_cert = pending_certificate_service.create_certificate(
                cert, real_cert, cert.user)
            pending_certificate_service.update(cert.id,
                                               resolved_cert_id=final_cert.id)
            pending_certificate_service.update(cert.id, resolved=True)
            # add metrics to metrics extension
            new += 1
        else:
            # Double check the pending certificate still exists in the database
            # before updating the failed attempt counter
            if not pending_certificate_service.get(cert.id):
                current_app.logger.info(
                    f"Not incrementing failed attempt counter because {cert.name} was cancelled before."
                )
            else:
                pending_certificate_service.increment_attempt(cert)
                failed += 1
    log_data["message"] = "Complete"
    log_data["new"] = new
    log_data["failed"] = failed
    current_app.logger.debug(log_data)
    metrics.send(f"{function}.resolved", "gauge", new)
    metrics.send(f"{function}.failed", "gauge", failed)
    print(f"[+] Certificates: New: {new} Failed: {failed}")
    return log_data
Esempio n. 13
0
    def get_ordered_certificates(self, pending_certs):
        pending = []
        certs = []
        for pending_cert in pending_certs:
            rejected = False
            expired = False
            try:

                authority = get_authority(pending_cert.authority_id)
                authority_name = authority.name.upper()

                # print("AUTHORITYNAME**** " + authority_name)

                session = requests.Session()
                session.mount('https://', HttpsAdapter())
                session.cert = current_app.config.get(
                    "EJBCA_PEM_PATH_{0}".format(authority_name))
                session.verify = current_app.config.get("EJBCA_TRUSTSTORE")
                session.hooks = dict(response=log_status_code)
                transport = Transport(session=session)
                url = current_app.config.get(
                    "EJBCA_URL") + "/ejbca/ejbcaws/ejbcaws?wsdl"

                client = Client(url, transport=transport)

                csr_x509 = load_certificate_request(FILETYPE_PEM,
                                                    pending_cert.csr)
                # get SubjectDN string from CSR
                subject_dn = get_subject_dn_string(
                    csr_x509.get_subject().get_components())
                # print("*****DN:" + subject_dn)

                end_entity_username = pending_cert.name
                if end_entity_username is None:
                    end_entity_username = "******"

                # Strip -[digit]+ from pending cert name to obtain end entity username
                end_entity_username = re.sub('-\d+$', '', end_entity_username)

                response = client.service.getRemainingNumberOfApprovals(
                    pending_cert.external_id)

                num_remaining = response
                current_app.logger.debug(
                    f"Remaining check: {str(num_remaining)}")

                if num_remaining == -1:
                    # print("Rejected!")
                    rejected = True
                    certs.append({
                        "cert": False,
                        "pending_cert": pending_cert,
                        "last_error": "Request was rejected",
                        "rejected": rejected,
                        "expired": expired
                    })
                elif num_remaining > 0:
                    current_app.logger.debug(
                        f"Remaining Approvals: {num_remaining}")
                    # print("Approvals Remaining")
                    remain_message = "Remaining approvals: " + str(
                        num_remaining)
                    certs.append({
                        "cert": False,
                        "pending_cert": pending_cert,
                        "last_error": remain_message,
                        "rejected": rejected,
                        "expired": expired
                    })
                elif num_remaining == 0:
                    #ready to issue cert
                    csr_b64 = dump_certificate_request(FILETYPE_PEM, csr_x509)
                    csr_b64 = csr_b64.decode()

                    request_data = {
                        'arg0': end_entity_username,
                        'arg1': 'foo123',
                        'arg2': csr_b64,
                        'arg3': None,
                        'arg4': 'CERTIFICATE'
                    }

                    try:
                        response = client.service.pkcs10Request(**request_data)

                        # print(response)
                        # print(response.data)

                        cert_data_str = response.data.decode("utf-8")

                        # print("CERT DATA")
                        # print(cert_data_str)
                        #cert_data = base64.b64decode(cert_data_str).decode("utf-8")
                        cert_data_str.replace('\\n', '\n')
                        # print("decoded:")
                        # print(cert_data_str)
                        external_id = None
                        #reconstruct certificate from json array
                        pem = "-----BEGIN CERTIFICATE-----\n"
                        pem += cert_data_str

                        pem += "\n-----END CERTIFICATE-----"

                        #authority = get_authority(pending_cert.authority_id)
                        #authority_name = authority.name.upper()
                        chain = current_app.config.get(
                            "EJBCA_INTERMEDIATE_{0}".format(authority_name),
                            current_app.config.get("EJBCA_INTERMEDIATE"))

                        cert = {
                            "body": pem,
                            "chain": "\n".join(str(chain).splitlines()),
                            "external_id": str(pending_cert.external_id),
                            "authority_id": str(pending_cert.authority_id),
                        }
                        certs.append({
                            "cert": cert,
                            "pending_cert": pending_cert
                        })

                    except zeep.exceptions.Fault as fault:
                        sentry.captureException()
                        metrics.send(
                            "get_ordered_certificates_pending_creation_error",
                            "counter", 1)
                        current_app.logger.error(
                            f"Unable to resolve EJBCA pending cert: {pending_cert}",
                            exc_info=True)

                        certs.append({
                            "cert": False,
                            "pending_cert": pending_cert,
                            "last_error": fault.message,
                            "rejected": rejected,
                            "expired": expired
                        })

            except zeep.exceptions.Fault as fault:
                strdet = fault.detail[0]
                m = re.search('^\{.*\}(.*)$', strdet.tag)
                exceptname = m.group(1)
                if (exceptname == "ApprovalRequestExpiredException"):
                    expired = True
                certs.append({
                    "cert": False,
                    "pending_cert": pending_cert,
                    "last_error": fault.message,
                    "rejected": rejected,
                    "expired": expired
                })

        return certs
Esempio n. 14
0
def fetch_acme_cert(id):
    """
    Attempt to get the full certificate for the pending certificate listed.

    Args:
        id: an id of a PendingCertificate
    """
    log_data = {
        "function": "{}.{}".format(__name__,
                                   sys._getframe().f_code.co_name)
    }
    pending_certs = pending_certificate_service.get_pending_certs([id])
    user = user_service.get_by_username('lemur')
    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 real_cert:
            # If a real certificate was returned from issuer, then create it in Lemur and delete
            # the pending certificate
            pending_certificate_service.create_certificate(
                pending_cert, real_cert, user)
            pending_certificate_service.delete_by_id(pending_cert.id)
            # 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 > 4:
                error_log["message"] = "Deleting pending certificate"
                send_pending_failure_notification(
                    pending_cert, notify_owner=pending_cert.notify)
                pending_certificate_service.delete(
                    pending_certificate_service.cancel(pending_cert))
            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)
            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)
    print(
        "[+] Certificates: New: {new} Failed: {failed} Not using ACME: {wrong_issuer}"
        .format(new=new, failed=failed, wrong_issuer=wrong_issuer))