diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 976d7ab12..336e6c4e5 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -228,6 +228,9 @@ class HTTP01Response(KeyAuthorizationChallengeResponse): """ + WHITESPACE_CUTSET = "\n\r\t " + """Whitespace characters which should be ignored at the end of the body.""" + def simple_verify(self, chall, domain, account_public_key, port=None): """Simple verify. @@ -273,10 +276,11 @@ class HTTP01Response(KeyAuthorizationChallengeResponse): found_ct, chall.CONTENT_TYPE) return False - if self.key_authorization != http_response.text: + challenge_response = http_response.text.rstrip(self.WHITESPACE_CUTSET) + if self.key_authorization != challenge_response: logger.debug("Key authorization from response (%r) doesn't match " "HTTP response (%r)", self.key_authorization, - http_response.text) + challenge_response) return False return True diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index c4f3d6c61..7cf387ece 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -126,6 +126,16 @@ class HTTP01ResponseTest(unittest.TestCase): self.assertFalse(self.response.simple_verify( self.chall, "local", KEY.public_key())) + @mock.patch("acme.challenges.requests.get") + def test_simple_verify_whitespace_validation(self, mock_get): + from acme.challenges import HTTP01Response + mock_get.return_value = mock.MagicMock( + text=(self.chall.validation(KEY) + + HTTP01Response.WHITESPACE_CUTSET), headers=self.good_headers) + self.assertTrue(self.response.simple_verify( + self.chall, "local", KEY.public_key())) + mock_get.assert_called_once_with(self.chall.uri("local")) + @mock.patch("acme.challenges.requests.get") def test_simple_verify_bad_content_type(self, mock_get): mock_get().text = self.chall.token