Use acme.challenges in acme.messages

This commit is contained in:
Jakub Warmuz
2015-02-25 13:56:47 +00:00
parent 0b8767f990
commit 9ba69f8878
2 changed files with 59 additions and 21 deletions
+21 -6
View File
@@ -3,6 +3,7 @@ import json
import jsonschema import jsonschema
from letsencrypt.acme import challenges
from letsencrypt.acme import errors from letsencrypt.acme import errors
from letsencrypt.acme import jose from letsencrypt.acme import jose
from letsencrypt.acme import other from letsencrypt.acme import other
@@ -96,11 +97,23 @@ class Challenge(Message):
fields["combinations"] = self.combinations fields["combinations"] = self.combinations
return fields return fields
@property
def resolved_combinations(self):
"""Combinations with challenges instead of indices."""
return [[self.challenges[idx] for idx in combo]
for combo in self.combinations]
@classmethod @classmethod
def from_valid_json(cls, jobj): def from_valid_json(cls, jobj):
# TODO: can challenges contain two challenges of the same type?
# TODO: can challenges contain duplicates?
# TODO: check "combinations" indices are in valid range
# TODO: turn "combinations" elements into sets?
# TODO: turn "combinations" into set?
return cls(session_id=jobj["sessionID"], return cls(session_id=jobj["sessionID"],
nonce=cls._decode_b64jose(jobj["nonce"]), nonce=cls._decode_b64jose(jobj["nonce"]),
challenges=jobj["challenges"], challenges=[challenges.Challenge.from_valid_json(chall)
for chall in jobj["challenges"]],
combinations=jobj.get("combinations", [])) combinations=jobj.get("combinations", []))
@@ -216,11 +229,13 @@ class AuthorizationRequest(Message):
@classmethod @classmethod
def from_valid_json(cls, jobj): def from_valid_json(cls, jobj):
return cls(session_id=jobj["sessionID"], return cls(
nonce=cls._decode_b64jose(jobj["nonce"]), session_id=jobj["sessionID"],
responses=jobj["responses"], nonce=cls._decode_b64jose(jobj["nonce"]),
signature=other.Signature.from_valid_json(jobj["signature"]), responses=[challenges.ChallengeResponse.from_valid_json(chall)
contact=jobj.get("contact", [])) for chall in jobj["responses"]],
signature=other.Signature.from_valid_json(jobj["signature"]),
contact=jobj.get("contact", []))
@Message.register # pylint: disable=too-few-public-methods @Message.register # pylint: disable=too-few-public-methods
+38 -15
View File
@@ -5,6 +5,7 @@ import unittest
import Crypto.PublicKey.RSA import Crypto.PublicKey.RSA
import M2Crypto.X509 import M2Crypto.X509
from letsencrypt.acme import challenges
from letsencrypt.acme import errors from letsencrypt.acme import errors
from letsencrypt.acme import jose from letsencrypt.acme import jose
from letsencrypt.acme import other from letsencrypt.acme import other
@@ -86,10 +87,10 @@ class MessageTest(unittest.TestCase):
class ChallengeTest(unittest.TestCase): class ChallengeTest(unittest.TestCase):
def setUp(self): def setUp(self):
challenges = [ challs = [
{'type': 'simpleHttps', 'token': 'IlirfxKKXAsHtmzK29Pj8A'}, challenges.SimpleHTTPS(token='IlirfxKKXAsHtmzK29Pj8A'),
{'type': 'dns', 'token': 'DGyRejmCefe7v4NfDGDKfA'}, challenges.DNS(token='DGyRejmCefe7v4NfDGDKfA'),
{'type': 'recoveryToken'}, challenges.RecoveryToken(),
] ]
combinations = [[0, 2], [1, 2]] combinations = [[0, 2], [1, 2]]
@@ -97,31 +98,52 @@ class ChallengeTest(unittest.TestCase):
self.msg = Challenge( self.msg = Challenge(
session_id='aefoGaavieG9Wihuk2aufai3aeZ5EeW4', session_id='aefoGaavieG9Wihuk2aufai3aeZ5EeW4',
nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9', nonce='\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9',
challenges=challenges, combinations=combinations) challenges=challs, combinations=combinations)
self.jmsg = { self.jmsg_to = {
'type': 'challenge', 'type': 'challenge',
'sessionID': 'aefoGaavieG9Wihuk2aufai3aeZ5EeW4', 'sessionID': 'aefoGaavieG9Wihuk2aufai3aeZ5EeW4',
'nonce': '7Nbyb1lI6xPVI3Hg3aKSqQ', 'nonce': '7Nbyb1lI6xPVI3Hg3aKSqQ',
'challenges': challenges, 'challenges': challs,
'combinations': combinations, 'combinations': combinations,
} }
self.jmsg_from = {
'type': 'challenge',
'sessionID': 'aefoGaavieG9Wihuk2aufai3aeZ5EeW4',
'nonce': '7Nbyb1lI6xPVI3Hg3aKSqQ',
'challenges': [chall.to_json() for chall in challs],
'combinations': combinations,
}
def test_resolved_combinations(self):
self.assertEqual(self.msg.resolved_combinations, [
[
challenges.SimpleHTTPS(token='IlirfxKKXAsHtmzK29Pj8A'),
challenges.RecoveryToken()
],
[
challenges.DNS(token='DGyRejmCefe7v4NfDGDKfA'),
challenges.RecoveryToken(),
]
])
def test_to_json(self): def test_to_json(self):
self.assertEqual(self.msg.to_json(), self.jmsg) self.assertEqual(self.msg.to_json(), self.jmsg_to)
def test_from_json(self): def test_from_json(self):
from letsencrypt.acme.messages import Challenge from letsencrypt.acme.messages import Challenge
self.assertEqual(Challenge.from_json(self.jmsg), self.msg) self.assertEqual(Challenge.from_json(self.jmsg_from), self.msg)
def test_json_without_optionals(self): def test_json_without_optionals(self):
del self.jmsg['combinations'] del self.jmsg_from['combinations']
del self.jmsg_to['combinations']
from letsencrypt.acme.messages import Challenge from letsencrypt.acme.messages import Challenge
msg = Challenge.from_json(self.jmsg) msg = Challenge.from_json(self.jmsg_from)
self.assertEqual(msg.combinations, []) self.assertEqual(msg.combinations, [])
self.assertEqual(msg.to_json(), self.jmsg) self.assertEqual(msg.to_json(), self.jmsg_to)
class ChallengeRequestTest(unittest.TestCase): class ChallengeRequestTest(unittest.TestCase):
@@ -186,9 +208,9 @@ class AuthorizationRequestTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.responses = [ self.responses = [
{'type': 'simpleHttps', 'path': 'Hf5GrX4Q7EBax9hc2jJnfw'}, challenges.SimpleHTTPSResponse(path='Hf5GrX4Q7EBax9hc2jJnfw'),
None, # null None, # null
{'type': 'recoveryToken', 'token': '23029d88d9e123e'}, challenges.RecoveryTokenResponse(token='23029d88d9e123e'),
] ]
self.contact = ["mailto:cert-admin@example.com", "tel:+12025551212"] self.contact = ["mailto:cert-admin@example.com", "tel:+12025551212"]
signature = other.Signature( signature = other.Signature(
@@ -220,7 +242,8 @@ class AuthorizationRequestTest(unittest.TestCase):
'type': 'authorizationRequest', 'type': 'authorizationRequest',
'sessionID': 'aefoGaavieG9Wihuk2aufai3aeZ5EeW4', 'sessionID': 'aefoGaavieG9Wihuk2aufai3aeZ5EeW4',
'nonce': '7Nbyb1lI6xPVI3Hg3aKSqQ', 'nonce': '7Nbyb1lI6xPVI3Hg3aKSqQ',
'responses': self.responses, 'responses': [None if response is None else response.to_json()
for response in self.responses],
'signature': signature.to_json(), 'signature': signature.to_json(),
'contact': self.contact, 'contact': self.contact,
} }