Integration test for ACMEv2 (#3298)
This commit is contained in:
parent
bdad6ddc4e
commit
b369818ad6
|
@ -39,6 +39,7 @@ matrix:
|
|||
- env: RUN="unit"
|
||||
- env: RUN="unit-next" BOULDER_CONFIG_DIR="test/config-next"
|
||||
- env: RUN="coverage"
|
||||
- env: RUN="acme-v2" BOULDER_CONFIG_DIR="test/config-next"
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: RUN="coverage"
|
||||
|
|
12
test.sh
12
test.sh
|
@ -188,6 +188,18 @@ if [[ "$RUN" =~ "integration" ]] ; then
|
|||
end_context #integration
|
||||
fi
|
||||
|
||||
if [[ "$RUN" =~ "acme-v2" ]] ; then
|
||||
# If you're developing against a local Certbot repo, edit docker-compose.yml
|
||||
# to mount it as a volume under /certbot, and run tests with
|
||||
# docker-compose run -e RUN=acme-v2 -e CERTBOT_REPO=/certbot boulder ./test.sh
|
||||
CERTBOT_REPO=${CERTBOT_REPO:-https://github.com/certbot/certbot}
|
||||
CERTBOT_DIR=$(mktemp -d -t certbotXXXX)
|
||||
git clone $CERTBOT_REPO $CERTBOT_DIR
|
||||
(cd $CERTBOT_DIR ; git checkout acme-v2-integration; ./tools/venv.sh)
|
||||
source $CERTBOT_DIR/venv/bin/activate
|
||||
REQUESTS_CA_BUNDLE=test/wfe.pem DIRECTORY=https://boulder:4431/directory run python2 test/integration-test-v2.py
|
||||
fi
|
||||
|
||||
# Run godep-restore (happens only in Travis) to check that the hashes in
|
||||
# Godeps.json really exist in the remote repo and match what we have.
|
||||
if [[ "$RUN" =~ "godep-restore" ]] ; then
|
||||
|
|
|
@ -23,11 +23,12 @@ from cryptography import x509
|
|||
from cryptography.hazmat.primitives import hashes
|
||||
|
||||
import OpenSSL
|
||||
import josepy
|
||||
|
||||
from acme import challenges
|
||||
from acme import client as acme_client
|
||||
from acme import crypto_util as acme_crypto_util
|
||||
from acme import errors as acme_errors
|
||||
from acme import jose
|
||||
from acme import messages
|
||||
from acme import standalone
|
||||
|
||||
|
@ -36,17 +37,18 @@ logger = logging.getLogger()
|
|||
logger.setLevel(int(os.getenv('LOGLEVEL', 0)))
|
||||
|
||||
DIRECTORY = os.getenv('DIRECTORY', 'http://localhost:4001/directory')
|
||||
ACCEPTABLE_TOS = "https://boulder:4431/terms/v7"
|
||||
|
||||
def make_client(email=None):
|
||||
"""Build an acme.Client and register a new account with a random key."""
|
||||
key = jose.JWKRSA(key=rsa.generate_private_key(65537, 2048, default_backend()))
|
||||
key = josepy.JWKRSA(key=rsa.generate_private_key(65537, 2048, default_backend()))
|
||||
|
||||
net = acme_client.ClientNetwork(key, verify_ssl=False,
|
||||
net = acme_client.ClientNetwork(key, acme_version=2,
|
||||
user_agent="Boulder integration tester")
|
||||
|
||||
client = acme_client.Client(DIRECTORY, key=key, net=net)
|
||||
client = acme_client.Client(DIRECTORY, key=key, net=net, acme_version=2)
|
||||
tos = client.directory.meta.terms_of_service
|
||||
if tos is not None and "Do%20what%20thou%20wilt" in tos:
|
||||
if tos == ACCEPTABLE_TOS:
|
||||
net.account = client.register(messages.NewRegistration.from_data(email=email,
|
||||
terms_of_service_agreed=True))
|
||||
else:
|
||||
|
@ -70,10 +72,10 @@ class ValidationError(Exception):
|
|||
return "%s: %s: %s" % (self.domain, self.problem_type, self.detail)
|
||||
|
||||
def make_csr(domains):
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend())
|
||||
return x509.CertificateSigningRequestBuilder().add_extension(
|
||||
x509.SubjectAlternativeName([x509.DNSName(d) for d in domains], critical=False)
|
||||
).sign(key, hashes.SHA256(), default_backend()).public_bytes(serialization.Encoding.PEM)
|
||||
key = OpenSSL.crypto.PKey()
|
||||
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
|
||||
pem = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
|
||||
return acme_crypto_util.make_csr(pem, domains, False)
|
||||
|
||||
def issue(client, authzs, cert_output=None):
|
||||
"""Given a list of authzs that are being processed by the server,
|
||||
|
@ -129,12 +131,7 @@ def auth_and_issue(domains, chall_type="http-01", email=None, cert_output=None,
|
|||
raise Exception("invalid challenge type %s" % chall_type)
|
||||
|
||||
try:
|
||||
while True:
|
||||
order, response = client.poll_order(order)
|
||||
print order.to_json()
|
||||
if order.body.status != "pending":
|
||||
break
|
||||
time.sleep(1)
|
||||
order = client.poll_order_and_request_issuance(order)
|
||||
finally:
|
||||
cleanup()
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Integration test for ACMEv2 as implemented by boulder-wfe2.
|
||||
|
||||
Currently (December 2017) this depends on the acme-v2-integration branch of
|
||||
Certbot, while we wait on landing some of our changes in master.
|
||||
"""
|
||||
import atexit
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import startservers
|
||||
|
||||
import chisel2
|
||||
from chisel2 import auth_and_issue
|
||||
|
||||
exit_status = 1
|
||||
tempdir = tempfile.mkdtemp()
|
||||
|
||||
def random_domain():
|
||||
"""Generate a random domain for testing (to avoid rate limiting)."""
|
||||
return "rand.%x.xyz" % random.randrange(2**32)
|
||||
|
||||
def main():
|
||||
if not startservers.start(race_detection=True):
|
||||
raise Exception("startservers failed")
|
||||
|
||||
test_multidomain()
|
||||
|
||||
if not startservers.check():
|
||||
raise Exception("startservers.check failed")
|
||||
|
||||
global exit_status
|
||||
exit_status = 0
|
||||
|
||||
def test_multidomain():
|
||||
auth_and_issue([random_domain(), random_domain()])
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise Exception("%s. Output:\n%s" % (e, e.output))
|
||||
|
||||
@atexit.register
|
||||
def stop():
|
||||
import shutil
|
||||
shutil.rmtree(tempdir)
|
||||
if exit_status == 0:
|
||||
print("\n\nSUCCESS")
|
||||
else:
|
||||
print("\n\nFAILURE")
|
Loading…
Reference in New Issue