mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 02:44:21 +02:00
Adjust achallanges to be used with ChallengeBody
This commit is contained in:
@@ -1,17 +1,20 @@
|
|||||||
"""Client annotated ACME challenges.
|
"""Client annotated ACME challenges.
|
||||||
|
|
||||||
Please use names such as ``achall`` to distiguish from variables "of type"
|
Please use names such as ``achall`` to distiguish from variables "of type"
|
||||||
:class:`letsencrypt.acme.challenges.Challenge` (denoted by ``chall``)::
|
:class:`letsencrypt.acme.challenges.Challenge` (denoted by ``chall``)
|
||||||
|
and :class:`.ChallengeBody` (denoted by ``challb``)::
|
||||||
|
|
||||||
from letsencrypt.acme import challenges
|
from letsencrypt.acme import challenges
|
||||||
|
from letsencrypt.acme import messages2
|
||||||
from letsencrypt.client import achallenges
|
from letsencrypt.client import achallenges
|
||||||
|
|
||||||
chall = challenges.DNS(token='foo')
|
chall = challenges.DNS(token='foo')
|
||||||
achall = achallenges.DNS(chall=chall, domain='example.com')
|
challb = messages2.ChallengeBody(chall=chall)
|
||||||
|
achall = achallenges.DNS(chall=challb, domain='example.com')
|
||||||
|
|
||||||
Note, that all annotated challenges act as a proxy objects::
|
Note, that all annotated challenges act as a proxy objects::
|
||||||
|
|
||||||
achall.token == chall.token
|
achall.token == challb.token
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from letsencrypt.acme import challenges
|
from letsencrypt.acme import challenges
|
||||||
@@ -29,19 +32,19 @@ class AnnotatedChallenge(jose_util.ImmutableMap):
|
|||||||
Wraps around server provided challenge and annotates with data
|
Wraps around server provided challenge and annotates with data
|
||||||
useful for the client.
|
useful for the client.
|
||||||
|
|
||||||
:ivar chall: Wrapped `~.ChallengeBody` (or just `~.challenges.Challenge`).
|
:ivar challb: Wrapped `~.ChallengeBody`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__slots__ = ('chall',)
|
__slots__ = ('challb',)
|
||||||
acme_type = NotImplemented
|
acme_type = NotImplemented
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.chall, name)
|
return getattr(self.challb, name)
|
||||||
|
|
||||||
|
|
||||||
class DVSNI(AnnotatedChallenge):
|
class DVSNI(AnnotatedChallenge):
|
||||||
"""Client annotated "dvsni" ACME challenge."""
|
"""Client annotated "dvsni" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain', 'key')
|
__slots__ = ('challb', 'domain', 'key')
|
||||||
acme_type = challenges.DVSNI
|
acme_type = challenges.DVSNI
|
||||||
|
|
||||||
def gen_cert_and_response(self, s=None): # pylint: disable=invalid-name
|
def gen_cert_and_response(self, s=None): # pylint: disable=invalid-name
|
||||||
@@ -55,35 +58,35 @@ class DVSNI(AnnotatedChallenge):
|
|||||||
"""
|
"""
|
||||||
response = challenges.DVSNIResponse(s=s)
|
response = challenges.DVSNIResponse(s=s)
|
||||||
cert_pem = crypto_util.make_ss_cert(self.key.pem, [
|
cert_pem = crypto_util.make_ss_cert(self.key.pem, [
|
||||||
self.nonce_domain, self.domain, response.z_domain(self.chall)])
|
self.nonce_domain, self.domain, response.z_domain(self.challb)])
|
||||||
return cert_pem, response
|
return cert_pem, response
|
||||||
|
|
||||||
|
|
||||||
class SimpleHTTPS(AnnotatedChallenge):
|
class SimpleHTTPS(AnnotatedChallenge):
|
||||||
"""Client annotated "simpleHttps" ACME challenge."""
|
"""Client annotated "simpleHttps" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain', 'key')
|
__slots__ = ('challb', 'domain', 'key')
|
||||||
acme_type = challenges.SimpleHTTPS
|
acme_type = challenges.SimpleHTTPS
|
||||||
|
|
||||||
|
|
||||||
class DNS(AnnotatedChallenge):
|
class DNS(AnnotatedChallenge):
|
||||||
"""Client annotated "dns" ACME challenge."""
|
"""Client annotated "dns" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain')
|
__slots__ = ('challb', 'domain')
|
||||||
acme_type = challenges.DNS
|
acme_type = challenges.DNS
|
||||||
|
|
||||||
|
|
||||||
class RecoveryContact(AnnotatedChallenge):
|
class RecoveryContact(AnnotatedChallenge):
|
||||||
"""Client annotated "recoveryContact" ACME challenge."""
|
"""Client annotated "recoveryContact" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain')
|
__slots__ = ('challb', 'domain')
|
||||||
acme_type = challenges.RecoveryContact
|
acme_type = challenges.RecoveryContact
|
||||||
|
|
||||||
|
|
||||||
class RecoveryToken(AnnotatedChallenge):
|
class RecoveryToken(AnnotatedChallenge):
|
||||||
"""Client annotated "recoveryToken" ACME challenge."""
|
"""Client annotated "recoveryToken" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain')
|
__slots__ = ('challb', 'domain')
|
||||||
acme_type = challenges.RecoveryToken
|
acme_type = challenges.RecoveryToken
|
||||||
|
|
||||||
|
|
||||||
class ProofOfPossession(AnnotatedChallenge):
|
class ProofOfPossession(AnnotatedChallenge):
|
||||||
"""Client annotated "proofOfPossession" ACME challenge."""
|
"""Client annotated "proofOfPossession" ACME challenge."""
|
||||||
__slots__ = ('chall', 'domain')
|
__slots__ = ('challb', 'domain')
|
||||||
acme_type = challenges.ProofOfPossession
|
acme_type = challenges.ProofOfPossession
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes
|
|||||||
for achall, resp in itertools.izip(achalls, resps):
|
for achall, resp in itertools.izip(achalls, resps):
|
||||||
# Don't send challenges for None and False authenticator responses
|
# Don't send challenges for None and False authenticator responses
|
||||||
if resp:
|
if resp:
|
||||||
challr = self.network.answer_challenge(achall.chall, resp)
|
challr = self.network.answer_challenge(achall.challb, resp)
|
||||||
if achall.domain in chall_update:
|
if achall.domain in chall_update:
|
||||||
chall_update[achall.domain].append(achall)
|
chall_update[achall.domain].append(achall)
|
||||||
else:
|
else:
|
||||||
@@ -267,31 +267,32 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes
|
|||||||
cont_chall = set()
|
cont_chall = set()
|
||||||
|
|
||||||
for index in path:
|
for index in path:
|
||||||
chall = self.authzr[domain].body.challenges[index]
|
challb = self.authzr[domain].body.challenges[index]
|
||||||
|
chall = challb.chall
|
||||||
|
|
||||||
if isinstance(chall, challenges.DVSNI):
|
if isinstance(chall, challenges.DVSNI):
|
||||||
logging.info(" DVSNI challenge for %s.", domain)
|
logging.info(" DVSNI challenge for %s.", domain)
|
||||||
achall = achallenges.DVSNI(
|
achall = achallenges.DVSNI(
|
||||||
chall=chall, domain=domain, key=self.authkey)
|
challb=challb, domain=domain, key=self.authkey)
|
||||||
elif isinstance(chall, challenges.SimpleHTTPS):
|
elif isinstance(chall, challenges.SimpleHTTPS):
|
||||||
logging.info(" SimpleHTTPS challenge for %s.", domain)
|
logging.info(" SimpleHTTPS challenge for %s.", domain)
|
||||||
achall = achallenges.SimpleHTTPS(
|
achall = achallenges.SimpleHTTPS(
|
||||||
chall=chall, domain=domain, key=self.authkey)
|
challb=challb, domain=domain, key=self.authkey)
|
||||||
elif isinstance(chall, challenges.DNS):
|
elif isinstance(chall, challenges.DNS):
|
||||||
logging.info(" DNS challenge for %s.", domain)
|
logging.info(" DNS challenge for %s.", domain)
|
||||||
achall = achallenges.DNS(chall=chall, domain=domain)
|
achall = achallenges.DNS(challb=challb, domain=domain)
|
||||||
|
|
||||||
elif isinstance(chall, challenges.RecoveryToken):
|
elif isinstance(chall, challenges.RecoveryToken):
|
||||||
logging.info(" Recovery Token Challenge for %s.", domain)
|
logging.info(" Recovery Token Challenge for %s.", domain)
|
||||||
achall = achallenges.RecoveryToken(chall=chall, domain=domain)
|
achall = achallenges.RecoveryToken(challb=challb, domain=domain)
|
||||||
elif isinstance(chall, challenges.RecoveryContact):
|
elif isinstance(chall, challenges.RecoveryContact):
|
||||||
logging.info(" Recovery Contact Challenge for %s.", domain)
|
logging.info(" Recovery Contact Challenge for %s.", domain)
|
||||||
achall = achallenges.RecoveryContact(
|
achall = achallenges.RecoveryContact(
|
||||||
chall=chall, domain=domain)
|
challb=challb, domain=domain)
|
||||||
elif isinstance(chall, challenges.ProofOfPossession):
|
elif isinstance(chall, challenges.ProofOfPossession):
|
||||||
logging.info(" Proof-of-Possession Challenge for %s", domain)
|
logging.info(" Proof-of-Possession Challenge for %s", domain)
|
||||||
achall = achallenges.ProofOfPossession(
|
achall = achallenges.ProofOfPossession(
|
||||||
chall=chall, domain=domain)
|
challb=challb, domain=domain)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise errors.LetsEncryptClientError(
|
raise errors.LetsEncryptClientError(
|
||||||
@@ -306,15 +307,15 @@ class AuthHandler(object): # pylint: disable=too-many-instance-attributes
|
|||||||
return dv_chall, cont_chall
|
return dv_chall, cont_chall
|
||||||
|
|
||||||
|
|
||||||
def gen_challenge_path(challs, preferences, combinations):
|
def gen_challenge_path(challbs, preferences, combinations):
|
||||||
"""Generate a plan to get authority over the identity.
|
"""Generate a plan to get authority over the identity.
|
||||||
|
|
||||||
.. todo:: This can be possibly be rewritten to use resolved_combinations.
|
.. todo:: This can be possibly be rewritten to use resolved_combinations.
|
||||||
|
|
||||||
:param tuple challs: A tuple of challenges
|
:param tuple challbs: A tuple of challenges
|
||||||
(:class:`letsencrypt.acme.challenges.Challenge`) from
|
(:class:`letsencrypt.acme.messages2.Challenge`) from
|
||||||
:class:`letsencrypt.acme.messages.Challenge` server message to
|
:class:`letsencrypt.acme.messages2.AuthorizationResource` to be
|
||||||
be fulfilled by the client in order to prove possession of the
|
fulfilled by the client in order to prove possession of the
|
||||||
identifier.
|
identifier.
|
||||||
|
|
||||||
:param list preferences: List of challenge preferences for domain
|
:param list preferences: List of challenge preferences for domain
|
||||||
@@ -333,12 +334,12 @@ def gen_challenge_path(challs, preferences, combinations):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if combinations:
|
if combinations:
|
||||||
return _find_smart_path(challs, preferences, combinations)
|
return _find_smart_path(challbs, preferences, combinations)
|
||||||
else:
|
else:
|
||||||
return _find_dumb_path(challs, preferences)
|
return _find_dumb_path(challbs, preferences)
|
||||||
|
|
||||||
|
|
||||||
def _find_smart_path(challs, preferences, combinations):
|
def _find_smart_path(challbs, preferences, combinations):
|
||||||
"""Find challenge path with server hints.
|
"""Find challenge path with server hints.
|
||||||
|
|
||||||
Can be called if combinations is included. Function uses a simple
|
Can be called if combinations is included. Function uses a simple
|
||||||
@@ -360,8 +361,8 @@ def _find_smart_path(challs, preferences, combinations):
|
|||||||
combo_total = 0
|
combo_total = 0
|
||||||
for combo in combinations:
|
for combo in combinations:
|
||||||
for challenge_index in combo:
|
for challenge_index in combo:
|
||||||
combo_total += chall_cost.get(challs[
|
combo_total += chall_cost.get(challbs[
|
||||||
challenge_index].__class__, max_cost)
|
challenge_index].chall.__class__, max_cost)
|
||||||
|
|
||||||
if combo_total < best_combo_cost:
|
if combo_total < best_combo_cost:
|
||||||
best_combo = combo
|
best_combo = combo
|
||||||
@@ -378,7 +379,7 @@ def _find_smart_path(challs, preferences, combinations):
|
|||||||
return best_combo
|
return best_combo
|
||||||
|
|
||||||
|
|
||||||
def _find_dumb_path(challs, preferences):
|
def _find_dumb_path(challbs, preferences):
|
||||||
"""Find challenge path without server hints.
|
"""Find challenge path without server hints.
|
||||||
|
|
||||||
Should be called if the combinations hint is not included by the
|
Should be called if the combinations hint is not included by the
|
||||||
@@ -391,11 +392,11 @@ def _find_dumb_path(challs, preferences):
|
|||||||
path = []
|
path = []
|
||||||
satisfied = set()
|
satisfied = set()
|
||||||
for pref_c in preferences:
|
for pref_c in preferences:
|
||||||
for i, offered_chall in enumerate(challs):
|
for i, offered_challb in enumerate(challbs):
|
||||||
if (isinstance(offered_chall, pref_c) and
|
if (isinstance(offered_challb.chall, pref_c) and
|
||||||
is_preferred(offered_chall, satisfied)):
|
is_preferred(offered_challb, satisfied)):
|
||||||
path.append(i)
|
path.append(i)
|
||||||
satisfied.add(offered_chall)
|
satisfied.add(offered_challb)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
@@ -415,11 +416,12 @@ def mutually_exclusive(obj1, obj2, groups, different=False):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def is_preferred(offered_chall, satisfied,
|
def is_preferred(offered_challb, satisfied,
|
||||||
exclusive_groups=constants.EXCLUSIVE_CHALLENGES):
|
exclusive_groups=constants.EXCLUSIVE_CHALLENGES):
|
||||||
"""Return whether or not the challenge is preferred in path."""
|
"""Return whether or not the challenge is preferred in path."""
|
||||||
for chall in satisfied:
|
for challb in satisfied:
|
||||||
if not mutually_exclusive(
|
if not mutually_exclusive(
|
||||||
offered_chall, chall, exclusive_groups, different=True):
|
offered_challb.chall, challb.chall, exclusive_groups,
|
||||||
|
different=True):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user