Merge pull request #860 from kuba/bugs/855

UnrecognizedChallenge (fixes #855).
This commit is contained in:
bmw 2015-09-29 08:52:15 -07:00
commit 74d96f9d92
4 changed files with 61 additions and 36 deletions

View file

@ -25,6 +25,14 @@ class Challenge(jose.TypedJSONObjectWithFields):
"""ACME challenge."""
TYPES = {}
@classmethod
def from_json(cls, jobj):
try:
return super(Challenge, cls).from_json(jobj)
except jose.UnrecognizedTypeError as error:
logger.debug(error)
return UnrecognizedChallenge.from_json(jobj)
class ContinuityChallenge(Challenge): # pylint: disable=abstract-method
"""Client validation challenges."""
@ -34,11 +42,6 @@ class DVChallenge(Challenge): # pylint: disable=abstract-method
"""Domain validation challenges."""
class UnrecognizedChallenge(Challenge):
"""Unrecognized challenge."""
typ = "unknown"
class ChallengeResponse(jose.TypedJSONObjectWithFields):
# _fields_to_partial_json | pylint: disable=abstract-method
"""ACME challenge response."""
@ -47,6 +50,32 @@ class ChallengeResponse(jose.TypedJSONObjectWithFields):
resource = fields.Resource(resource_type)
class UnrecognizedChallenge(Challenge):
"""Unrecognized challenge.
ACME specification defines a generic framework for challenges and
defines some standard challenges that are implemented in this
module. However, other implementations (including peers) might
define additional challenge types, which should be ignored if
unrecognized.
:ivar jobj: Original JSON decoded object.
"""
def __init__(self, jobj):
super(UnrecognizedChallenge, self).__init__()
object.__setattr__(self, "jobj", jobj)
def to_partial_json(self):
# pylint: disable=no-member
return self.jobj
@classmethod
def from_json(cls, jobj):
return cls(jobj)
@Challenge.register
class SimpleHTTP(DVChallenge):
"""ACME "simpleHttp" challenge.

View file

@ -17,6 +17,32 @@ CERT = test_util.load_cert('cert.pem')
KEY = test_util.load_rsa_private_key('rsa512_key.pem')
class ChallengeTest(unittest.TestCase):
def test_from_json_unrecognized(self):
from acme.challenges import Challenge
from acme.challenges import UnrecognizedChallenge
chall = UnrecognizedChallenge({"type": "foo"})
# pylint: disable=no-member
self.assertEqual(chall, Challenge.from_json(chall.jobj))
class UnrecognizedChallengeTest(unittest.TestCase):
def setUp(self):
from acme.challenges import UnrecognizedChallenge
self.jobj = {"type": "foo"}
self.chall = UnrecognizedChallenge(self.jobj)
def test_to_partial_json(self):
self.assertEqual(self.jobj, self.chall.to_partial_json())
def test_from_json(self):
from acme.challenges import UnrecognizedChallenge
self.assertEqual(
self.chall, UnrecognizedChallenge.from_json(self.jobj))
class SimpleHTTPTest(unittest.TestCase):
def setUp(self):

View file

@ -373,19 +373,7 @@ class Authorization(ResourceBody):
@challenges.decoder
def challenges(value): # pylint: disable=missing-docstring,no-self-argument
# The from_json method raises errors.UnrecognizedTypeError when a
# challenge of unknown type is encountered. We want to ignore this
# case. This forces us to do an explicit iteration, since list
# comprehensions can't handle exceptions.
challs = []
for chall in value:
try:
challs.append(ChallengeBody.from_json(chall))
except jose.UnrecognizedTypeError:
challs.append(ChallengeBody(
uri="UNKNOWN", chall=challenges.UnrecognizedChallenge,
status=STATUS_UNKNOWN))
return tuple(challs)
return tuple(ChallengeBody.from_json(chall) for chall in value)
@property
def resolved_combinations(self):

View file

@ -301,19 +301,6 @@ class AuthorizationTest(unittest.TestCase):
'combinations': combinations,
}
# For unknown challenge types
self.jmsg_unknown_chall = {
'resource': 'challenge',
'uri': 'random_uri',
'type': 'unknown',
'tls': True,
}
self.jobj_from_unknown = {
'identifier': identifier.to_json(),
'challenges': [self.jmsg_unknown_chall],
}
def test_from_json(self):
from acme.messages import Authorization
Authorization.from_json(self.jobj_from)
@ -328,11 +315,6 @@ class AuthorizationTest(unittest.TestCase):
(self.challbs[1], self.challbs[2]),
))
def test_unknown_chall_type(self):
"""Just make sure an error isn't thrown."""
from acme.messages import Authorization
Authorization.from_json(self.jobj_from_unknown)
class AuthorizationResourceTest(unittest.TestCase):
"""Tests for acme.messages.AuthorizationResource."""