Remove tls-sni in compatibility tests (#6854)

* Reconfigure compatibility tests to use http challenge

* Correct simple test

* Add a fake DNS resolution for HTTP simple_verify

* Debug

* More subtle approach: we monkey patch urllib3 to fake a dns resolution to the target IP, allowing every host header to be preserved.

* Private package

* Relaxed permissions on certbot temp working dir

* Move the fake DNS logic in compatibility test, to avoid degrading the acme coverage

* Fix lint

* Update certbot-compatibility-test/certbot_compatibility_test/configurators/common.py

Co-Authored-By: adferrand <adferrand@users.noreply.github.com>
This commit is contained in:
Adrien Ferrand
2019-03-15 01:07:49 +01:00
committed by GitHub
parent 5e64349a4a
commit c2f2aa5ee0
2 changed files with 33 additions and 11 deletions
@@ -23,6 +23,9 @@ class Proxy(object):
def __init__(self, args): def __init__(self, args):
"""Initializes the plugin with the given command line args""" """Initializes the plugin with the given command line args"""
self._temp_dir = tempfile.mkdtemp() self._temp_dir = tempfile.mkdtemp()
# tempfile.mkdtemp() creates folders with too restrictive permissions to be accessible
# to an Apache worker, leading to HTTP challenge failures. Let's fix that.
os.chmod(self._temp_dir, 0o755)
self.le_config = util.create_le_config(self._temp_dir) self.le_config = util.create_le_config(self._temp_dir)
config_dir = util.extract_configs(args.configs, self._temp_dir) config_dir = util.extract_configs(args.configs, self._temp_dir)
self._configs = [ self._configs = [
@@ -1,5 +1,6 @@
"""Tests Certbot plugins against different server configurations.""" """Tests Certbot plugins against different server configurations."""
import argparse import argparse
import contextlib
import filecmp import filecmp
import logging import logging
import os import os
@@ -7,6 +8,7 @@ import shutil
import tempfile import tempfile
import time import time
import sys import sys
from urllib3.util import connection
import OpenSSL import OpenSSL
@@ -64,18 +66,19 @@ def test_authenticator(plugin, config, temp_dir):
"Plugin failed to complete %s for %s in %s", "Plugin failed to complete %s for %s in %s",
type(achalls[i]), achalls[i].domain, config) type(achalls[i]), achalls[i].domain, config)
success = False success = False
elif isinstance(responses[i], challenges.TLSSNI01Response): elif isinstance(responses[i], challenges.HTTP01Response):
verified = responses[i].simple_verify(achalls[i].chall, # We fake the DNS resolution to ensure that any domain is resolved
achalls[i].domain, # to the local HTTP server setup for the compatibility tests
util.JWK.public_key(), with _fake_dns_resolution("127.0.0.1"):
host="127.0.0.1", verified = responses[i].simple_verify(
port=plugin.https_port) achalls[i].chall, achalls[i].domain,
util.JWK.public_key(), port=plugin.http_port)
if verified: if verified:
logger.info( logger.info(
"tls-sni-01 verification for %s succeeded", achalls[i].domain) "http-01 verification for %s succeeded", achalls[i].domain)
else: else:
logger.error( logger.error(
"**** tls-sni-01 verification for %s in %s failed", "**** http-01 verification for %s in %s failed",
achalls[i].domain, config) achalls[i].domain, config)
success = False success = False
@@ -102,9 +105,9 @@ def _create_achalls(plugin):
for domain in names: for domain in names:
prefs = plugin.get_chall_pref(domain) prefs = plugin.get_chall_pref(domain)
for chall_type in prefs: for chall_type in prefs:
if chall_type == challenges.TLSSNI01: if chall_type == challenges.HTTP01:
chall = challenges.TLSSNI01( chall = challenges.HTTP01(
token=os.urandom(challenges.TLSSNI01.TOKEN_SIZE)) token=os.urandom(challenges.HTTP01.TOKEN_SIZE))
challb = acme_util.chall_to_challb( challb = acme_util.chall_to_challb(
chall, messages.STATUS_PENDING) chall, messages.STATUS_PENDING)
achall = achallenges.KeyAuthorizationAnnotatedChallenge( achall = achallenges.KeyAuthorizationAnnotatedChallenge(
@@ -369,5 +372,21 @@ def main():
sys.exit(1) sys.exit(1)
@contextlib.contextmanager
def _fake_dns_resolution(resolved_ip):
"""Monkey patch urllib3 to make any hostname be resolved to the provided IP"""
_original_create_connection = connection.create_connection
def _patched_create_connection(address, *args, **kwargs):
_, port = address
return _original_create_connection((resolved_ip, port), *args, **kwargs)
try:
connection.create_connection = _patched_create_connection
yield
finally:
connection.create_connection = _original_create_connection
if __name__ == "__main__": if __name__ == "__main__":
main() main()