示例#1
0
def test_expired_authz_purger():
    def expect(target_time, num, table):
        out = get_future_output("./bin/expired-authz-purger --config cmd/expired-authz-purger/config.json", target_time)
        if 'via FAKECLOCK' not in out:
            raise Exception("expired-authz-purger was not built with `integration` build tag")
        if num is None:
            return
        expected_output = 'Deleted a total of %d expired authorizations from %s' % (num, table)
        if expected_output not in out:
            raise Exception("expired-authz-purger did not print '%s'.  Output:\n%s" % (
                  expected_output, out))

    now = datetime.datetime.utcnow()

    # Run the purger once to clear out any backlog so we have a clean slate.
    expect(now+datetime.timedelta(days=+365), None, "")

    # Make an authz, but don't attempt its challenges.
    chisel.make_client().request_domain_challenges("eap-test.com")

    # Run the authz twice: Once immediate, expecting nothing to be purged, and
    # once as if it were the future, expecting one purged authz.
    after_grace_period = now + datetime.timedelta(days=+14, minutes=+3)
    expect(now, 0, "pendingAuthorizations")
    expect(after_grace_period, 1, "pendingAuthorizations")

    auth_and_issue([random_domain()])
    after_grace_period = now + datetime.timedelta(days=+67, minutes=+3)
    expect(now, 0, "authz")
    expect(after_grace_period, 1, "authz")
示例#2
0
def run_expired_authz_purger():
    # Note: This test must be run after all other tests that depend on
    # authorizations added to the database during setup
    # (e.g. test_expired_authzs_404).

    def expect(target_time, num, table):
        tool = "expired-authz-purger2"
        out = get_future_output("./bin/expired-authz-purger2 --single-run --config cmd/expired-authz-purger2/config.json", target_time)
        if 'via FAKECLOCK' not in out:
            raise Exception("%s was not built with `integration` build tag" % (tool))
        if num is None:
            return
        expected_output = 'deleted %d expired authorizations' % (num)
        if expected_output not in out:
            raise Exception("%s did not print '%s'.  Output:\n%s" % (
                  tool, expected_output, out))

    now = datetime.datetime.utcnow()

    # Run the purger once to clear out any backlog so we have a clean slate.
    expect(now+datetime.timedelta(days=+365), None, "")

    # Make an authz, but don't attempt its challenges.
    chisel.make_client().request_domain_challenges("eap-test.com")

    # Run the authz twice: Once immediate, expecting nothing to be purged, and
    # once as if it were the future, expecting one purged authz.
    after_grace_period = now + datetime.timedelta(days=+14, minutes=+3)
    expect(now, 0, "pendingAuthorizations")
    expect(after_grace_period, 1, "pendingAuthorizations")

    auth_and_issue([random_domain()])
    after_grace_period = now + datetime.timedelta(days=+67, minutes=+3)
    expect(now, 0, "authz")
    expect(after_grace_period, 1, "authz")
示例#3
0
def test_expired_authz_purger():
    def expect(target_time, num):
        expected_output = ''
        if num is not None:
            expected_output = 'Deleted a total of %d expired pending authorizations' % num

        try:
            out = get_future_output("./bin/expired-authz-purger --config cmd/expired-authz-purger/config.json --yes", target_time)
            if expected_output not in out:
                print(("expired-authz-purger did not print '%s'. " +
                      "Maybe not built with `integration` build tag? Output:\n%s") % (
                      expected_output, out))
                die(ExitStatus.NodeFailure)
        except subprocess.CalledProcessError as e:
            print("\nFailed to run authz purger: %s" % e)
            die(ExitStatus.NodeFailure)

    now = datetime.datetime.utcnow()

    # Run the purger once to clear out any backlog so we have a clean slate.
    expect(now, None)

    # Make an authz, but don't attempt its challenges.
    chisel.make_client().request_domain_challenges("eap-test.com")

    # Run the authz twice: Once immediate, expecting nothing to be purged, and
    # once as if it were the future, expecting one purged authz.
    after_grace_period = now + datetime.timedelta(days=+14, minutes=+3)
    expect(now, 0)
    expect(after_grace_period, 1)
示例#4
0
def test_caa_extensions():
    goodCAA = "happy-hacker-ca.invalid"

    client = chisel.make_client()
    caa_account_uri = client.account.uri
    caa_records = [
        {"domain": "accounturi.good-caa-reserved.com", "value":"{0}; accounturi={1}".format(goodCAA, caa_account_uri)},
        {"domain": "dns-01-only.good-caa-reserved.com", "value": "{0}; validationmethods=dns-01".format(goodCAA)},
        {"domain": "http-01-only.good-caa-reserved.com", "value": "{0}; validationmethods=http-01".format(goodCAA)},
        {"domain": "dns-01-or-http01.good-caa-reserved.com", "value": "{0}; validationmethods=dns-01,http-01".format(goodCAA)},
    ]
    for policy in caa_records:
        challSrv.add_caa_issue(policy["domain"], policy["value"])

    # TODO(@4a6f656c): Once the `CAAValidationMethods` feature flag is enabled by
    # default, remove this early return.
    if not CONFIG_NEXT:
        return

    chisel.expect_problem("urn:acme:error:caa",
        lambda: auth_and_issue(["dns-01-only.good-caa-reserved.com"], chall_type="http-01"))

    chisel.expect_problem("urn:acme:error:caa",
        lambda: auth_and_issue(["http-01-only.good-caa-reserved.com"], chall_type="dns-01"))

    # Note: the additional names are to avoid rate limiting...
    auth_and_issue(["dns-01-only.good-caa-reserved.com", "www.dns-01-only.good-caa-reserved.com"], chall_type="dns-01")
    auth_and_issue(["http-01-only.good-caa-reserved.com", "www.http-01-only.good-caa-reserved.com"], chall_type="http-01")
    auth_and_issue(["dns-01-or-http-01.good-caa-reserved.com", "dns-01-only.good-caa-reserved.com"], chall_type="dns-01")
    auth_and_issue(["dns-01-or-http-01.good-caa-reserved.com", "http-01-only.good-caa-reserved.com"], chall_type="http-01")

    # CAA should fail with an arbitrary account, but succeed with the CAA client.
    chisel.expect_problem("urn:acme:error:caa", lambda: auth_and_issue(["accounturi.good-caa-reserved.com"]))
    auth_and_issue(["accounturi.good-caa-reserved.com"], client=client)
示例#5
0
def test_http_challenge_http_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")
    # Calculate its keyauth so we can add it in a special non-standard location
    # for the redirect result
    resp = chall.response(client.key)
    keyauth = resp.key_authorization
    challSrv.add_http01_response("http-redirect", keyauth)

    # Create a HTTP redirect from the challenge's validation path to some other
    # token path where we have registered the key authorization.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    redirectPath = "/.well-known/acme-challenge/http-redirect?params=are&important=to&not=lose"
    challSrv.add_http_redirect(
        challengePath,
        "http://{0}{1}".format(d, redirectPath))

    # Issuing should succeed
    auth_and_issue([d], client=client, chall_type="http-01")

    # Cleanup the redirects
    challSrv.remove_http_redirect(challengePath)
    challSrv.remove_http01_response("http-redirect")

    history = challSrv.http_request_history(d)
    challSrv.clear_http_request_history(d)

    # There should have been at least two GET requests made to the
    # challtestsrv. There may have been more if remote VAs were configured.
    if len(history) < 2:
        raise Exception("Expected at least 2 HTTP request events on challtestsrv, found {1}".format(len(history)))

    initialRequests = []
    redirectedRequests = []

    for request in history:
      # All requests should have been over HTTP
      if request['HTTPS'] is True:
        raise Exception("Expected all requests to be HTTP")
      # Initial requests should have the expected initial HTTP-01 URL for the challenge
      if request['URL'] == challengePath:
        initialRequests.append(request)
      # Redirected requests should have the expected redirect path URL with all
      # its parameters
      elif request['URL'] == redirectPath:
        redirectedRequests.append(request)
      else:
        raise Exception("Unexpected request URL {0} in challtestsrv history: {1}".format(request['URL'], request))

    # There should have been at least 1 initial HTTP-01 validation request.
    if len(initialRequests) < 1:
        raise Exception("Expected {0} initial HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(initialRequests)))

    # There should have been at least 1 redirected HTTP request for each VA
    if len(redirectedRequests) < 1:
        raise Exception("Expected {0} redirected HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(redirectedRequests)))
示例#6
0
def test_http_challenge_http_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")
    # Calculate its keyauth so we can add it in a special non-standard location
    # for the redirect result
    resp = chall.response(client.key)
    keyauth = resp.key_authorization
    challSrv.add_http01_response("http-redirect", keyauth)

    # Create a HTTP redirect from the challenge's validation path to some other
    # token path where we have registered the key authorization.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    redirectPath = "/.well-known/acme-challenge/http-redirect?params=are&important=to&not=lose"
    challSrv.add_http_redirect(
        challengePath,
        "http://{0}{1}".format(d, redirectPath))

    # Issuing should succeed
    auth_and_issue([d], client=client, chall_type="http-01")

    # Cleanup the redirects
    challSrv.remove_http_redirect(challengePath)
    challSrv.remove_http01_response("http-redirect")

    history = challSrv.http_request_history(d)
    challSrv.clear_http_request_history(d)

    # There should have been at least two GET requests made to the
    # challtestsrv. There may have been more if remote VAs were configured.
    if len(history) < 2:
        raise Exception("Expected at least 2 HTTP request events on challtestsrv, found {1}".format(len(history)))

    initialRequests = []
    redirectedRequests = []

    for request in history:
      # All requests should have been over HTTP
      if request['HTTPS'] is True:
        raise Exception("Expected all requests to be HTTP")
      # Initial requests should have the expected initial HTTP-01 URL for the challenge
      if request['URL'] == challengePath:
        initialRequests.append(request)
      # Redirected requests should have the expected redirect path URL with all
      # its parameters
      elif request['URL'] == redirectPath:
        redirectedRequests.append(request)
      else:
        raise Exception("Unexpected request URL {0} in challtestsrv history: {1}".format(request['URL'], request))

    # There should have been at least 1 initial HTTP-01 validation request.
    if len(initialRequests) < 1:
        raise Exception("Expected {0} initial HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(initialRequests)))

    # There should have been at least 1 redirected HTTP request for each VA
    if len(redirectedRequests) < 1:
        raise Exception("Expected {0} redirected HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(redirectedRequests)))
示例#7
0
def test_revoke_by_account():
    cert_file_pem = os.path.join(tempdir, "revokeme.pem")
    client = chisel.make_client()
    cert, _ = auth_and_issue([random_domain()], client=client)
    client.revoke(cert.body)

    wait_for_ocsp_revoked(cert_file_pem, "test/test-ca2.pem", ee_ocsp_url)
    return 0
示例#8
0
def caa_recheck_setup():
    global caa_recheck_client
    caa_recheck_client = chisel.make_client()
    # Issue a certificate with the clock set back, and save the authzs to check
    # later that they are valid (200). They should however require rechecking for
    # CAA purposes.
    _, authzs = auth_and_issue([random_domain()], client=caa_recheck_client)
    for a in authzs:
        caa_recheck_authzs.append(a)
示例#9
0
def setup_twenty_days_ago():
    """Do any setup that needs to happen 20 day in the past, for tests that
       will run in the 'present'.
    """
    # Issue a certificate with the clock set back, and save the authzs to check
    # later that they are valid (200). They should however require rechecking for
    # CAA purposes.
    global caa_client
    caa_client = chisel.make_client()
    global caa_authzs
    _, caa_authzs = auth_and_issue(["recheck.good-caa-reserved.com"], client=caa_client)
示例#10
0
def test_auth_deactivation():
    client = chisel.make_client(None)
    auth = client.request_domain_challenges(random_domain())
    resp = client.deactivate_authorization(auth)
    if resp.body.status is not messages.STATUS_DEACTIVATED:
        raise Exception("unexpected authorization status")

    _, auth = auth_and_issue([random_domain()], client=client)
    resp = client.deactivate_authorization(auth[0])
    if resp.body.status is not messages.STATUS_DEACTIVATED:
        raise Exception("unexpected authorization status")
示例#11
0
def setup_twenty_days_ago():
    """Do any setup that needs to happen 20 day in the past, for tests that
       will run in the 'present'.
    """
    # Issue a certificate with the clock set back, and save the authzs to check
    # later that they are valid (200). They should however require rechecking for
    # CAA purposes.
    global caa_client
    caa_client = chisel.make_client()
    global caa_authzs
    _, caa_authzs = auth_and_issue(["recheck.good-caa-reserved.com"], client=caa_client)
示例#12
0
def test_revoke_by_account():
    client = chisel.make_client()
    cert, _ = auth_and_issue([random_domain()], client=client)
    client.revoke(cert.body, 0)

    cert_file_pem = os.path.join(tempdir, "revokeme.pem")
    with open(cert_file_pem, "w") as f:
        f.write(OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, cert.body.wrapped).decode())
    ee_ocsp_url = "http://localhost:4002"
    wait_for_ocsp_revoked(cert_file_pem, "test/test-ca2.pem", ee_ocsp_url)
    return 0
示例#13
0
def test_revoke_by_account():
    client = chisel.make_client()
    cert, _ = auth_and_issue([random_domain()], client=client)
    client.revoke(cert.body, 0)

    cert_file_pem = os.path.join(tempdir, "revokeme.pem")
    with open(cert_file_pem, "w") as f:
        f.write(OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, cert.body.wrapped).decode())
    ee_ocsp_url = "http://localhost:4002"
    wait_for_ocsp_revoked(cert_file_pem, "test/test-ca2.pem", ee_ocsp_url)
    return 0
示例#14
0
def caa_recheck_setup():
    global caa_recheck_client
    caa_recheck_client = chisel.make_client()
    # Issue a certificate with the clock set back, and save the authzs to check
    # later that they are valid (200). They should however require rechecking for
    # CAA purposes.
    numNames = 10
    # Generate numNames subdomains of a random domain
    base_domain = random_domain()
    domains = ["{0}.{1}".format(str(n), base_domain) for n in range(numNames)]
    _, authzs = auth_and_issue(domains, client=caa_recheck_client)
    for a in authzs:
        caa_recheck_authzs.append(a)
示例#15
0
def test_revoke_by_account():
    client = chisel.make_client()
    cert_file = temppath('test_revoke_by_account.pem')
    cert, _ = auth_and_issue([random_domain()],
                             client=client,
                             cert_output=cert_file.name)

    reset_akamai_purges()
    client.revoke(cert.body, 0)

    verify_ocsp(cert_file.name, "/tmp/intermediate-cert-sm2-a.pem",
                "http://localhost:4002", "revoked")

    verify_akamai_purge()
示例#16
0
def test_admin_revoker_authz():
    # Make an authz, but don't attempt its challenges.
    authz_resource = chisel.make_client().request_domain_challenges("ar-auth-test.com")
    url = authz_resource.uri
    # Revoke authorization by domain
    output = run(
            "./bin/admin-revoker auth-revoke --config %s/admin-revoker.json ar-auth-test.com" % (default_config_dir))
    if not output.rstrip().endswith("Revoked 1 pending authorizations and 0 final authorizations"):
        raise Exception("admin-revoker didn't revoke the expected number of pending and finalized authorizations")
    # Check authorization has actually been revoked
    response = urllib2.urlopen(url)
    data = json.loads(response.read())
    if data['status'] != "revoked":
        raise Exception("Authorization wasn't revoked")
示例#17
0
def test_http_challenge_https_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to an HTTPS
    # address with the same path.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(challengePath, "https://{0}{1}".format(d, challengePath))

    auth_and_issue([d], client=client, chall_type="http-01")

    remove_http_redirect(challengePath)
示例#18
0
def test_revoke_by_account():
    client = chisel.make_client()
    cert, _ = auth_and_issue([random_domain()], client=client)
    reset_akamai_purges()
    client.revoke(cert.body, 0)

    cert_file_pem = os.path.join(tempdir, "revokeme.pem")
    with open(cert_file_pem, "w") as f:
        f.write(
            OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                            cert.body.wrapped).decode())
    ee_ocsp_url = "http://localhost:4002"
    verify_ocsp(cert_file_pem, "/tmp/intermediate-cert-rsa-a.pem", ee_ocsp_url,
                "revoked")
    verify_akamai_purge()
    return 0
示例#19
0
def test_revoke_by_account():
    client = chisel.make_client()
    cert, _ = auth_and_issue([random_domain()], client=client)
    reset_akamai_purges()
    client.revoke(cert.body, 0)

    cert_file_pem = os.path.join(tempdir, "revokeme.pem")
    with open(cert_file_pem, "w") as f:
        f.write(OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, cert.body.wrapped).decode())
    ee_ocsp_url = "http://localhost:4002"
    if default_config_dir.startswith("test/config-next"):
        verify_revocation(cert_file_pem, "test/test-ca2.pem", ee_ocsp_url)
    else:
        wait_for_ocsp_revoked(cert_file_pem, "test/test-ca2.pem", ee_ocsp_url)
    verify_akamai_purge()
    return 0
示例#20
0
def test_account_update():
    """
    Create a new ACME client/account with one contact email. Then update the
    account to a different contact emails.
    """
    emails=("*****@*****.**", "*****@*****.**", "*****@*****.**")
    client = chisel.make_client(email=emails[0])

    for email in emails[1:]:
        result = chisel.update_email(client, email=email)
        # We expect one contact in the result
        if len(result.body.contact) != 1:
            raise Exception("\nUpdate account failed: expected one contact in result, got 0")
        # We expect it to be the email we just updated to
        actual = result.body.contact[0]
        if actual != "mailto:"+email:
            raise Exception("\nUpdate account failed: expected contact %s, got %s" % (email, actual))
示例#21
0
def test_http_challenge_loop_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to itself
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(challengePath, "http://{0}{1}".format(d, challengePath))

    # Issuing for the the name should fail because of the challenge domains's
    # redirect loop.
    chisel.expect_problem(
        "urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    remove_http_redirect(challengePath)
示例#22
0
def test_http_challenge_loop_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to itself
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    challSrv.add_http_redirect(
        challengePath,
        "http://{0}{1}".format(d, challengePath))

    # Issuing for the the name should fail because of the challenge domains's
    # redirect loop.
    chisel.expect_problem("urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    challSrv.remove_http_redirect(challengePath)
示例#23
0
def test_http_challenge_badhost_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to a
    # non public hostname.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    challSrv.add_http_redirect(challengePath,
                               "https://example.lan{0}".format(challengePath))

    # Issuing for the name should cause a connection error because the redirect
    # domain name is an not end in IANA registered TLD.
    chisel.expect_problem(
        "urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    challSrv.remove_http_redirect(challengePath)
示例#24
0
def test_admin_revoker_authz():
    # Make an authz, but don't attempt its challenges.
    authz_resource = chisel.make_client().request_domain_challenges("ar-auth-test.com")
    url = authz_resource.uri
    # Revoke authorization by domain
    try:
        output = subprocess.check_output(
                "./bin/admin-revoker auth-revoke --config %s/admin-revoker.json ar-auth-test.com" % (default_config_dir), shell=True)
    except subprocess.CalledProcessError as e:
        print("Failed to revoke authorization: %s", e)
        die(ExitStatus.RevokerFailure)
    if not output.rstrip().endswith("Revoked 1 pending authorizations and 0 final authorizations"):
        print("admin-revoker didn't revoke the expected number of pending and finalized authorizations")
        die(ExitStatus.RevokerFailure)
    # Check authorization has actually been revoked
    response = urllib2.urlopen(url)
    data = json.loads(response.read())
    if data['status'] != "revoked":
        print("Authorization wasn't revoked")
        die(ExitStatus.RevokerFailure)
示例#25
0
def test_http_challenge_badproto_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to whacky
    # non-http/https protocol URL.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(challengePath,
                      "gopher://{0}{1}".format(d, challengePath))

    # Issuing for the name should cause a connection error because the redirect
    # URL an invalid protocol scheme.
    chisel.expect_problem(
        "urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    remove_http_redirect(challengePath)
示例#26
0
def test_http_challenge_badhost_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to a bare IP
    # hostname.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(challengePath,
                      "https://127.0.0.1{0}".format(challengePath))

    # Issuing for the name should cause a connection error because the redirect
    # domain name is an IP address.
    chisel.expect_problem(
        "urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    remove_http_redirect(challengePath)
示例#27
0
def test_http_challenge_badhost_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to a bare IP
    # hostname.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    challSrv.add_http_redirect(
        challengePath,
        "https://127.0.0.1{0}".format(challengePath))

    # Issuing for the name should cause a connection error because the redirect
    # domain name is an IP address.
    chisel.expect_problem("urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    challSrv.remove_http_redirect(challengePath)
示例#28
0
def test_http_challenge_badproto_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to whacky
    # non-http/https protocol URL.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    challSrv.add_http_redirect(
        challengePath,
        "gopher://{0}{1}".format(d, challengePath))

    # Issuing for the name should cause a connection error because the redirect
    # URL an invalid protocol scheme.
    chisel.expect_problem("urn:acme:error:connection",
        lambda: auth_and_issue([d], client=client, chall_type="http-01"))

    challSrv.remove_http_redirect(challengePath)
示例#29
0
def test_http_challenge_http_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")
    # Calculate its keyauth so we can add it in a special non-standard location
    # for the redirect result
    resp = chall.response(client.key)
    keyauth = resp.key_authorization
    add_http01_response("http-redirect", keyauth)

    # Create a HTTP redirect from the challenge's validation path to some other
    # token path where we have registered the key authorization.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(
        challengePath,
        "http://{0}/.well-known/acme-challenge/http-redirect".format(d))

    auth_and_issue([d], client=client, chall_type="http-01")

    remove_http_redirect(challengePath)
    remove_http01_response("http-redirect")
示例#30
0
def test_http_challenge_https_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")

    # Create a HTTP redirect from the challenge's validation path to an HTTPS
    # address with the same path.
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    add_http_redirect(challengePath, "https://{0}{1}".format(d, challengePath))

    # Also add an A record for the domain pointing to the interface that the
    # HTTPS HTTP-01 challtestsrv is bound.
    urllib2.urlopen("{0}/add-a".format(challsrv_url_base),
                    data=json.dumps({
                        "host": d,
                        "addresses": ["10.77.77.77"],
                    })).read()

    auth_and_issue([d], client=client, chall_type="http-01")

    remove_http_redirect(challengePath)
示例#31
0
def main():
    parser = argparse.ArgumentParser(description='Run integration tests')
    parser.add_argument('--all',
                        dest="run_all",
                        action="store_true",
                        help="run all of the clients' integration tests")
    parser.add_argument('--certbot',
                        dest='run_certbot',
                        action='store_true',
                        help="run the certbot integration tests")
    parser.add_argument('--chisel',
                        dest="run_chisel",
                        action="store_true",
                        help="run integration tests using chisel")
    parser.add_argument('--load',
                        dest="run_loadtest",
                        action="store_true",
                        help="run load-generator")
    parser.add_argument('--filter',
                        dest="test_case_filter",
                        action="store",
                        help="Regex filter for test cases")
    parser.add_argument('--skip-setup',
                        dest="skip_setup",
                        action="store_true",
                        help="skip integration test setup")
    # allow any ACME client to run custom command for integration
    # testing (without having to implement its own busy-wait loop)
    parser.add_argument('--custom', metavar="CMD", help="run custom command")
    parser.set_defaults(run_all=False,
                        run_certbot=False,
                        run_chisel=False,
                        run_loadtest=False,
                        test_case_filter="",
                        skip_setup=False)
    args = parser.parse_args()

    if not (args.run_all or args.run_certbot or args.run_chisel
            or args.run_loadtest or args.custom is not None):
        raise Exception(
            "must run at least one of the letsencrypt or chisel tests with --all, --certbot, --chisel, --load or --custom"
        )

    if not args.skip_setup:
        now = datetime.datetime.utcnow()
        seventy_days_ago = now + datetime.timedelta(days=-70)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(seventy_days_ago)):
            raise Exception("startservers failed (mocking seventy days ago)")
        setup_seventy_days_ago()
        global caa_client
        caa_client = chisel.make_client()
        startservers.stop()

        now = datetime.datetime.utcnow()
        twenty_days_ago = now + datetime.timedelta(days=-20)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(twenty_days_ago)):
            raise Exception("startservers failed (mocking twenty days ago)")
        setup_twenty_days_ago()
        startservers.stop()

    caa_acount_uri = caa_client.account.uri if caa_client is not None else None
    if not startservers.start(race_detection=True, account_uri=caa_acount_uri):
        raise Exception("startservers failed")

    if not args.skip_setup:
        setup_zero_days_ago()

    if args.run_all or args.run_chisel:
        run_chisel(args.test_case_filter)

    if args.run_all or args.run_certbot:
        run_client_tests()

    if args.run_all or args.run_loadtest:
        run_loadtest()

    if args.custom:
        run(args.custom)

    run_cert_checker()
    check_balance()
    run_expired_authz_purger()

    if not startservers.check():
        raise Exception("startservers.check failed")

    global exit_status
    exit_status = 0
示例#32
0
def main():
    parser = argparse.ArgumentParser(description='Run integration tests')
    parser.add_argument('--all', dest="run_all", action="store_true",
                        help="run all of the clients' integration tests")
    parser.add_argument('--certbot', dest='run_certbot', action='store_true',
                        help="run the certbot integration tests")
    parser.add_argument('--chisel', dest="run_chisel", action="store_true",
                        help="run integration tests using chisel")
    parser.add_argument('--load', dest="run_loadtest", action="store_true",
                        help="run load-generator")
    parser.add_argument('--filter', dest="test_case_filter", action="store",
                        help="Regex filter for test cases")
    parser.add_argument('--skip-setup', dest="skip_setup", action="store_true",
                        help="skip integration test setup")
    # allow any ACME client to run custom command for integration
    # testing (without having to implement its own busy-wait loop)
    parser.add_argument('--custom', metavar="CMD", help="run custom command")
    parser.set_defaults(run_all=False, run_certbot=False, run_chisel=False,
        run_loadtest=False, test_case_filter="", skip_setup=False)
    args = parser.parse_args()

    if not (args.run_all or args.run_certbot or args.run_chisel or args.run_loadtest or args.custom is not None):
        raise Exception("must run at least one of the letsencrypt or chisel tests with --all, --certbot, --chisel, --load or --custom")

    if not args.skip_setup:
        now = datetime.datetime.utcnow()
        seventy_days_ago = now+datetime.timedelta(days=-70)
        if not startservers.start(race_detection=True, fakeclock=fakeclock(seventy_days_ago)):
            raise Exception("startservers failed (mocking seventy days ago)")
        setup_seventy_days_ago()
        global caa_client
        caa_client = chisel.make_client()
        startservers.stop()

        now = datetime.datetime.utcnow()
        twenty_days_ago = now+datetime.timedelta(days=-20)
        if not startservers.start(race_detection=True, fakeclock=fakeclock(twenty_days_ago)):
            raise Exception("startservers failed (mocking twenty days ago)")
        setup_twenty_days_ago()
        startservers.stop()

    caa_account_uri = caa_client.account.uri if caa_client is not None else None
    if not startservers.start(race_detection=True, account_uri=caa_account_uri):
        raise Exception("startservers failed")

    if not args.skip_setup:
        setup_zero_days_ago()

    setup_mock_dns(caa_account_uri)

    if args.run_all or args.run_chisel:
        run_chisel(args.test_case_filter)

    if args.run_all or args.run_certbot:
        run_client_tests()

    if args.run_all or args.run_loadtest:
        run_loadtest()

    if args.custom:
        run(args.custom)

    run_cert_checker()
    check_balance()
    run_expired_authz_purger()

    if not startservers.check():
        raise Exception("startservers.check failed")

    global exit_status
    exit_status = 0
示例#33
0
def test_http_challenge_https_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")
    # Calculate its keyauth so we can add it in a special non-standard location
    # for the redirect result
    resp = chall.response(client.key)
    keyauth = resp.key_authorization
    challSrv.add_http01_response("https-redirect", keyauth)

    # Create a HTTP redirect from the challenge's validation path to an HTTPS
    # path with some parameters
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    redirectPath = "/.well-known/acme-challenge/https-redirect?params=are&important=to&not=lose"
    challSrv.add_http_redirect(
        challengePath,
        "https://{0}{1}".format(d, redirectPath))


    # Also add an A record for the domain pointing to the interface that the
    # HTTPS HTTP-01 challtestsrv is bound.
    challSrv.add_a_record(d, ["10.77.77.77"])

    auth_and_issue([d], client=client, chall_type="http-01")

    challSrv.remove_http_redirect(challengePath)
    challSrv.remove_a_record(d)

    history = challSrv.http_request_history(d)
    challSrv.clear_http_request_history(d)

    # There should have been at least two GET requests made to the challtestsrv by the VA
    if len(history) < 2:
        raise Exception("Expected 2 HTTP request events on challtestsrv, found {0}".format(len(history)))

    initialRequests = []
    redirectedRequests = []

    for request in history:
      # Initial requests should have the expected initial HTTP-01 URL for the challenge
      if request['URL'] == challengePath:
        initialRequests.append(request)
      # Redirected requests should have the expected redirect path URL with all
      # its parameters
      elif request['URL'] == redirectPath:
        redirectedRequests.append(request)
      else:
        raise Exception("Unexpected request URL {0} in challtestsrv history: {1}".format(request['URL'], request))

    # There should have been at least 1 initial HTTP-01 validation request.
    if len(initialRequests) < 1:
        raise Exception("Expected {0} initial HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(initialRequests)))
     # All initial requests should have been over HTTP
    for r in initialRequests:
      if r['HTTPS'] is True:
        raise Exception("Expected all initial requests to be HTTP")

    # There should have been at least 1 redirected HTTP request for each VA
    if len(redirectedRequests) < 1:
        raise Exception("Expected {0} redirected HTTP-01 request events on challtestsrv, found {1}".format(validation_attempts, len(redirectedRequests)))
    # All the redirected requests should have been over HTTPS with the correct
    # SNI value
    for r in redirectedRequests:
      if r['HTTPS'] is False:
        raise Exception("Expected all redirected requests to be HTTPS")
      elif r['ServerName'] != d:
        raise Exception("Expected all redirected requests to have ServerName {0} got \"{1}\"".format(d, r['ServerName']))
示例#34
0
def test_http_challenge_https_redirect():
    client = chisel.make_client()

    # Create an authz for a random domain and get its HTTP-01 challenge token
    d, chall = rand_http_chall(client)
    token = chall.encode("token")
    # Calculate its keyauth so we can add it in a special non-standard location
    # for the redirect result
    resp = chall.response(client.key)
    keyauth = resp.key_authorization
    challSrv.add_http01_response("https-redirect", keyauth)

    # Create a HTTP redirect from the challenge's validation path to an HTTPS
    # path with some parameters
    challengePath = "/.well-known/acme-challenge/{0}".format(token)
    redirectPath = "/.well-known/acme-challenge/https-redirect?params=are&important=to&not=lose"
    challSrv.add_http_redirect(challengePath,
                               "https://{0}{1}".format(d, redirectPath))

    # Also add an A record for the domain pointing to the interface that the
    # HTTPS HTTP-01 challtestsrv is bound.
    challSrv.add_a_record(d, ["10.77.77.77"])

    auth_and_issue([d], client=client, chall_type="http-01")

    challSrv.remove_http_redirect(challengePath)
    challSrv.remove_a_record(d)

    history = challSrv.http_request_history(d)
    challSrv.clear_http_request_history(d)

    # There should have been at least two GET requests made to the challtestsrv by the VA
    if len(history) < 2:
        raise (Exception(
            "Expected 2 HTTP request events on challtestsrv, found {0}".format(
                len(history))))

    initialRequests = []
    redirectedRequests = []

    for request in history:
        # Initial requests should have the expected initial HTTP-01 URL for the challenge
        if request['URL'] == challengePath:
            initialRequests.append(request)
        # Redirected requests should have the expected redirect path URL with all
        # its parameters
        elif request['URL'] == redirectPath:
            redirectedRequests.append(request)
        else:
            raise (Exception(
                "Unexpected request URL {0} in challtestsrv history: {1}".
                format(request['URL'], request)))

    # There should have been at least 1 initial HTTP-01 validation request.
    if len(initialRequests) < 1:
        raise (Exception(
            "Expected {0} initial HTTP-01 request events on challtestsrv, found {1}"
            .format(validation_attempts, len(initialRequests))))
    # All initial requests should have been over HTTP
    for r in initialRequests:
        if r['HTTPS'] is True:
            raise (Exception("Expected all initial requests to be HTTP"))

    # There should have been at least 1 redirected HTTP request for each VA
    if len(redirectedRequests) < 1:
        raise (Exception(
            "Expected {0} redirected HTTP-01 request events on challtestsrv, found {1}"
            .format(validation_attempts, len(redirectedRequests))))
    # All the redirected requests should have been over HTTPS with the correct
    # SNI value
    for r in redirectedRequests:
        if r['HTTPS'] is False:
            raise (Exception("Expected all redirected requests to be HTTPS"))
        elif r['ServerName'] != d:
            raise (Exception(
                "Expected all redirected requests to have ServerName {0} got \"{1}\""
                .format(d, r['ServerName'])))
示例#35
0
def main():
    parser = argparse.ArgumentParser(description='Run integration tests')
    parser.add_argument('--certbot',
                        dest='run_certbot',
                        action='store_true',
                        help="run the certbot integration tests")
    parser.add_argument('--chisel',
                        dest="run_chisel",
                        action="store_true",
                        help="run integration tests using chisel")
    parser.add_argument('--filter',
                        dest="test_case_filter",
                        action="store",
                        help="Regex filter for test cases")
    # allow any ACME client to run custom command for integration
    # testing (without having to implement its own busy-wait loop)
    parser.add_argument('--custom', metavar="CMD", help="run custom command")
    parser.set_defaults(run_certbot=False,
                        run_chisel=False,
                        test_case_filter="",
                        skip_setup=False)
    args = parser.parse_args()

    if not (args.run_certbot or args.run_chisel or args.run_loadtest
            or args.custom is not None):
        raise Exception(
            "must run at least one of the letsencrypt or chisel tests with --certbot, --chisel, or --custom"
        )

    if not args.test_case_filter:
        now = datetime.datetime.utcnow()

        six_months_ago = now + datetime.timedelta(days=-30 * 6)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(six_months_ago)):
            raise Exception("startservers failed (mocking six months ago)")
        v1_integration.caa_client = caa_client = chisel.make_client()
        setup_six_months_ago()
        startservers.stop()

        twenty_days_ago = now + datetime.timedelta(days=-20)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(twenty_days_ago)):
            raise Exception("startservers failed (mocking twenty days ago)")
        setup_twenty_days_ago()
        startservers.stop()

    if not startservers.start(race_detection=True):
        raise Exception("startservers failed")

    if args.run_chisel:
        run_chisel(args.test_case_filter)

    if args.run_certbot:
        run_client_tests()

    run_go_tests()

    if args.custom:
        run(args.custom)

    # Skip the last-phase checks when the test case filter is one, because that
    # means we want to quickly iterate on a single test case.
    if not args.test_case_filter:
        run_cert_checker()
        check_balance()
        if not CONFIG_NEXT:
            run_expired_authz_purger()

        # Run the boulder-janitor. This should happen after all other tests because
        # it runs with the fake clock set to the future and deletes rows that may
        # otherwise be referenced by tests.
        run_janitor()

        # Run the load-generator last. run_loadtest will stop the
        # pebble-challtestsrv before running the load-generator and will not restart
        # it.
        run_loadtest()

    if not startservers.check():
        raise Exception("startservers.check failed")

    global exit_status
    exit_status = 0
示例#36
0
def main():
    parser = argparse.ArgumentParser(description='Run integration tests')
    parser.add_argument('--all',
                        dest="run_all",
                        action="store_true",
                        help="run all of the clients' integration tests")
    parser.add_argument('--certbot',
                        dest='run_certbot',
                        action='store_true',
                        help="run the certbot integration tests")
    parser.add_argument('--chisel',
                        dest="run_chisel",
                        action="store_true",
                        help="run integration tests using chisel")
    parser.add_argument('--load',
                        dest="run_loadtest",
                        action="store_true",
                        help="run load-generator")
    parser.add_argument('--filter',
                        dest="test_case_filter",
                        action="store",
                        help="Regex filter for test cases")
    parser.add_argument('--skip-setup',
                        dest="skip_setup",
                        action="store_true",
                        help="skip integration test setup")
    # allow any ACME client to run custom command for integration
    # testing (without having to implement its own busy-wait loop)
    parser.add_argument('--custom', metavar="CMD", help="run custom command")
    parser.set_defaults(run_all=False,
                        run_certbot=False,
                        run_chisel=False,
                        run_loadtest=False,
                        test_case_filter="",
                        skip_setup=False)
    args = parser.parse_args()

    if not (args.run_all or args.run_certbot or args.run_chisel
            or args.run_loadtest or args.custom is not None):
        raise Exception(
            "must run at least one of the letsencrypt or chisel tests with --all, --certbot, --chisel, --load or --custom"
        )

    caa_client = None
    if not args.skip_setup:
        now = datetime.datetime.utcnow()
        seventy_days_ago = now + datetime.timedelta(days=-70)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(seventy_days_ago)):
            raise Exception("startservers failed (mocking seventy days ago)")
        setup_seventy_days_ago()
        v1_integration.caa_client = caa_client = chisel.make_client()
        startservers.stop()

        now = datetime.datetime.utcnow()
        twenty_days_ago = now + datetime.timedelta(days=-20)
        if not startservers.start(race_detection=True,
                                  fakeclock=fakeclock(twenty_days_ago)):
            raise Exception("startservers failed (mocking twenty days ago)")
        setup_twenty_days_ago()
        startservers.stop()

    if not startservers.start(race_detection=True):
        raise Exception("startservers failed")

    if not args.skip_setup:
        setup_zero_days_ago()

    if args.run_all or args.run_chisel:
        run_chisel(args.test_case_filter)

    if args.run_all or args.run_certbot:
        run_client_tests()

    if args.custom:
        run(args.custom)

    run_cert_checker()
    # Skip load-balancing check when test case filter is on, since that usually
    # means there's a single issuance and we don't expect every RPC backend to get
    # traffic.
    if not args.test_case_filter:
        check_balance()
    if not CONFIG_NEXT:
        run_expired_authz_purger()

    # Run the load-generator last. run_loadtest will stop the
    # pebble-challtestsrv before running the load-generator and will not restart
    # it.
    if args.run_all or args.run_loadtest:
        run_loadtest()

    if not startservers.check():
        raise Exception("startservers.check failed")

    global exit_status
    exit_status = 0