def submit_domain_validation(client, regr, account, challenges_file, domain, log):
    # Get challenges for the domain.
    challg1 = get_challenges(client, regr, domain, challenges_file, log)
    challg = challg1.body

    if challg.status.name == "valid":
        # This is already valid. Return it immediately.
        return challg1
    elif challg.status.name != "pending":
        raise ChallengesUnknownStatus()

    # Look for a challenge combination that we can fulfill.
    for combination in challg.combinations:
        if len(combination) == 1:
            chg = challg.challenges[combination[0]]
            if isinstance(chg.chall, acme.challenges.SimpleHTTP):
                if chg.status.name != "pending":
                    # We can't submit twice. If this challenge is still pending
                    # but the overall challg object is not valid, then I'm not
                    # sure how to proceed.
                    raise ChallengesUnknownStatus()

                # Submit the SimpleHTTP challenge, raising NeedToInstallFile if
                # the conditions are not yet met.
                chg = answer_challenge_simplehttp(
                    domain,
                    chg.chall,
                    client,
                    account,
                    chg,
                    log)

                # The ChallengeResource probably comes back still pending because
                # it doesn't go THAT fast. Give it a moment, then poll.
                time.sleep(1)
                challg1, resp = client.poll(challg1)
                if challg1.body.status.name == "valid":
                    # It's valid now. That was fast.
                    return challg1

                # It's not valid. Tell the user they must want.
                retry_after = client.retry_after(resp, default=60)
                raise WaitABit(retry_after)

    raise NoChallengeMethodsSupported()
def get_challenges(client, regr, domain, challenges_file, log):
    # Load any existing challenges we've requested for domains so we
    # can track the challenges we've requested across sessions.
    existing_challenges = []
    if os.path.exists(challenges_file):
        with open(challenges_file) as f:
            existing_challenges = json.load(f)

    # Load.
    for i in range(len(existing_challenges)):
        existing_challenges[i] = \
            acme.messages.AuthorizationResource.from_json(existing_challenges[i])

    # Drop any challenges that have expired.
    existing_challenges = list(filter(lambda challg: is_still_valid(challg.body.expires), existing_challenges))

    # If challenges exist for this domain, reuse it.
    for i, challg in enumerate(existing_challenges):
        if challg.body.identifier.typ.name == "dns" and challg.body.identifier.value == domain:
            log("Reusing existing challenges for %s." % domain)

            # Refresh the record because it may have been updated with validated challenges.
            challg, resp = client.poll(challg)
            existing_challenges[i] = challg
            break
    else:
        # None found.
        challg = None

    if challg is None:
        # Get new challenges for a domain.
        log("Requesting new challenges for %s." % domain)
        challg = client.request_domain_challenges(domain, regr.new_authzr_uri)

        # Add into our existing challenges.
        existing_challenges.append(challg)

    # Save new set of challenges.
    with open(challenges_file, 'w') as f:
        f.write(json.dumps([c.to_json() for c in existing_challenges], sort_keys=True, indent=4))

    # Return the new challenges for this domain.
    return challg
def get_challenges(client, regr, domain, challenges_file, log):
    # Load the cache of challenges.
    challenges = load_challenges_file(challenges_file)

    # If challenges exist for this domain, reuse it.
    # We've already dropped expired and revoked challenges, so we don't have
    # to check that here.
    for i, challg in enumerate(challenges):
        if challg.body.identifier.typ.name == "dns" and challg.body.identifier.value == domain:
            log("Reusing existing challenges for %s." % domain)

            # Refresh the record because it may have been updated with validated challenges.
            try:
                challg, resp = client.poll(challg)
            except acme.messages.Error as e:
                if e.typ in ("urn:acme:error:unauthorized",
                             "urn:acme:error:malformed"):
                    # There is a problem accessing our own account. This probably
                    # means the stored registration information is not valid.
                    raise AccountDataIsCorrupt(challenges_file)
                raise

            # Check that the refreshed record is not expired/revoked. Those
            # aren't helpful. It might be "invalid", meaning a challenge
            # failed. We'll percolate up an invalid challenge so the user
            # gets a ChallengeFailed exception, but we'll also drop it from
            # the cache so that it doesn't prevent further attempts to get
            # a certificate from proceeding.
            if is_still_valid_challenge(challg):
                if challg.body.status.name != "invalid":
                    # Update cache.
                    challenges[i] = challg
                else:
                    # Drop from cache.
                    challenges.pop(i)

                # Stop loop here: Use this challenge.
                break
    else:
        # None found.
        challg = None
        resp = None

    if challg is None:
        # Get new challenges for a domain.
        log("Requesting new challenges for %s." % domain)
        try:
            challg = client.request_domain_challenges(domain,
                                                      regr.new_authzr_uri)
        except acme.messages.Error as e:
            if e.typ == "urn:acme:error:malformed":
                raise InvalidDomainName(domain, e.detail)
            raise

        # Add into our existing challenges.
        challenges.append(challg)

    # Write a cache of challenges.
    save_challenges_file(challenges, challenges_file)

    # Return the new challenges for this domain, and if we updated it,
    # then the response object so we can know how long to wait before
    # polling again.
    return (challg, resp)
Example #4
0
def _getChallenges(hostname):
	# Load the cache of challenges.
	# Load any existing challenges we've requested for domains so we
	# can track the challenges we've requested across sessions.
	challenges = []
	domain = hostname + DOMAIN
	info = _recallHost(hostname)
	key = serialization.load_pem_private_key(base64.b64decode(info['acct_privkey']),password=None, backend=default_backend())
	client = acme.client.Client(CA,jose.JWKRSA(key=jose.ComparableRSAKey(key)))
	regr = acme.messages.RegistrationResource.json_loads(info['reg_json'])
	if not info['authz_json'] == None:
		challenges = json.loads(info['authz_json'])

	# Convert from JSON to ACME objects.
	for i in range(len(challenges)):
		challenges[i] = acme.messages.AuthorizationResource.from_json(challenges[i])

	# Drop any challenges that have expired or have been revoked.
	challenges = [challg for challg in challenges if not challg.body.status.name == "revoked" and ((challg.body.expires.replace(tzinfo=None)-datetime.now()) > timedelta(seconds=60))]

	# If challenges exist for this domain, reuse it.
	# We've already dropped expired and revoked challenges, so we don't have
	# to check that here.
	for i, challg in enumerate(challenges):
		if challg.body.identifier.typ.name == "dns" and challg.body.identifier.value == domain:
			print ("Reusing existing challenges for %s." % domain)

			# Refresh the record because it may have been updated with validated challenges.
			try:
				challg, resp = client.poll(challg)
			except acme.messages.Error as e:
				if e.typ in ("urn:acme:error:unauthorized", "urn:acme:error:malformed"):
					# There is a problem accessing our own account. This probably
					# means the stored registration information is not valid.
					raise AccountDataIsCorrupt(challenges_file)
				raise

			# Check that the refreshed record is still valid.
			if  not challg.body.status.name == "revoked" and ((challg.body.expires.replace(tzinfo=None)-datetime.now()) > timedelta(seconds=60)):
				# If so, keep it.
				challenges[i] = challg
				break
	else:
		# None found.
		challg = None
		resp = None

	if challg is None:
		# Get new challenges for a domain.
		print ("Requesting new challenges for %s." % domain)
		try:
			challg = client.request_domain_challenges(domain, regr.new_authzr_uri)
		except acme.messages.Error as e:
			#if e.typ == "urn:acme:error:malformed":
				#print e.detail
			print e.detail
			raise

		# Add into our existing challenges.
		challenges.append(challg)

	# Write a cache of challenges.
	_updateHost(hostname, 'authz_json', json.dumps([c.to_json() for c in challenges], sort_keys=True, indent=4))
	

	# Return the new challenges for this domain, and if we updated it,
	# then the response object so we can know how long to wait before
	# polling again.
	return (challg, resp)
def get_challenges(client, regr, domain, challenges_file, log):
    # Load the cache of challenges.
    challenges = load_challenges_file(challenges_file)

    # If challenges exist for this domain, reuse it.
    # We've already dropped expired and revoked challenges, so we don't have
    # to check that here.
    for i, challg in enumerate(challenges):
        if challg.body.identifier.typ.name == "dns" and challg.body.identifier.value == domain:
            log("Reusing existing challenges for %s." % domain)

            # Refresh the record because it may have been updated with validated challenges.
            try:
                challg, resp = client.poll(challg)
            except acme.messages.Error as e:
                if e.typ in ("urn:acme:error:unauthorized", "urn:acme:error:malformed"):
                    # There is a problem accessing our own account. This probably
                    # means the stored registration information is not valid.
                    raise AccountDataIsCorrupt(challenges_file)
                raise

            # Check that the refreshed record is not expired/revoked. Those
            # aren't helpful. It might be "invalid", meaning a challenge
            # failed. We'll percolate up an invalid challenge so the user
            # gets a ChallengeFailed exception, but we'll also drop it from
            # the cache so that it doesn't prevent further attempts to get
            # a certificate from proceeding.
            if is_still_valid_challenge(challg):
                if challg.body.status.name != "invalid":
                    # Update cache.
                    challenges[i] = challg
                else:
                    # Drop from cache.
                    challenges.pop(i)

                # Stop loop here: Use this challenge.
                break
    else:
        # None found.
        challg = None
        resp = None

    if challg is None:
        # Get new challenges for a domain.
        log("Requesting new challenges for %s." % domain)
        try:
            challg = client.request_domain_challenges(domain, regr.new_authzr_uri)
        except acme.messages.Error as e:
            if e.typ == "urn:acme:error:malformed":
                raise InvalidDomainName(domain, e.detail)
            raise

        # Add into our existing challenges.
        challenges.append(challg)

    # Write a cache of challenges.
    save_challenges_file(challenges, challenges_file)

    # Return the new challenges for this domain, and if we updated it,
    # then the response object so we can know how long to wait before
    # polling again.
    return (challg, resp)