Merge pull request #474 from kuba/nginx-apache-split

letsencrypt_nginx should not depend on letsencrypt_apache.
This commit is contained in:
James Kasten 2015-06-20 12:57:31 -04:00
commit 5dcac29e3b
14 changed files with 314 additions and 287 deletions

View file

@ -1,8 +1,14 @@
"""Plugin common functions."""
import os
import pkg_resources
import shutil
import tempfile
import zope.interface
from acme.jose import util as jose_util
from letsencrypt import constants
from letsencrypt import interfaces
@ -69,3 +75,127 @@ class Plugin(object):
with unique plugin name prefix.
"""
# other
class Addr(object):
r"""Represents an virtual host address.
:param str addr: addr part of vhost address
:param str port: port number or \*, or ""
"""
def __init__(self, tup):
self.tup = tup
@classmethod
def fromstring(cls, str_addr):
"""Initialize Addr from string."""
tup = str_addr.partition(':')
return cls((tup[0], tup[2]))
def __str__(self):
if self.tup[1]:
return "%s:%s" % self.tup
return self.tup[0]
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.tup == other.tup
return False
def __hash__(self):
return hash(self.tup)
def get_addr(self):
"""Return addr part of Addr object."""
return self.tup[0]
def get_port(self):
"""Return port."""
return self.tup[1]
def get_addr_obj(self, port):
"""Return new address object with same addr and new port."""
return self.__class__((self.tup[0], port))
class Dvsni(object):
"""Class that perform DVSNI challenges."""
def __init__(self, configurator):
self.configurator = configurator
self.achalls = []
self.indices = []
self.challenge_conf = os.path.join(
configurator.config.config_dir, "le_dvsni_cert_challenge.conf")
# self.completed = 0
def add_chall(self, achall, idx=None):
"""Add challenge to DVSNI object to perform at once.
:param achall: Annotated DVSNI challenge.
:type achall: :class:`letsencrypt.achallenges.DVSNI`
:param int idx: index to challenge in a larger array
"""
self.achalls.append(achall)
if idx is not None:
self.indices.append(idx)
def get_cert_file(self, achall):
"""Returns standardized name for challenge certificate.
:param achall: Annotated DVSNI challenge.
:type achall: :class:`letsencrypt.achallenges.DVSNI`
:returns: certificate file name
:rtype: str
"""
return os.path.join(
self.configurator.config.work_dir, achall.nonce_domain + ".crt")
def _setup_challenge_cert(self, achall, s=None):
# pylint: disable=invalid-name
"""Generate and write out challenge certificate."""
cert_path = self.get_cert_file(achall)
# Register the path before you write out the file
self.configurator.reverter.register_file_creation(True, cert_path)
cert_pem, response = achall.gen_cert_and_response(s)
# Write out challenge cert
with open(cert_path, "w") as cert_chall_fd:
cert_chall_fd.write(cert_pem)
return response
# test utils
def setup_ssl_options(config_dir, mod_ssl_conf):
"""Move the ssl_options into position and return the path."""
option_path = os.path.join(config_dir, "options-ssl.conf")
shutil.copyfile(mod_ssl_conf, option_path)
return option_path
def dir_setup(test_dir, pkg):
"""Setup the directories necessary for the configurator."""
temp_dir = tempfile.mkdtemp("temp")
config_dir = tempfile.mkdtemp("config")
work_dir = tempfile.mkdtemp("work")
os.chmod(temp_dir, constants.CONFIG_DIRS_MODE)
os.chmod(config_dir, constants.CONFIG_DIRS_MODE)
os.chmod(work_dir, constants.CONFIG_DIRS_MODE)
test_configs = pkg_resources.resource_filename(
pkg, os.path.join("testdata", test_dir))
shutil.copytree(
test_configs, os.path.join(temp_dir, test_dir), symlinks=True)
return temp_dir, config_dir, work_dir

View file

@ -1,8 +1,16 @@
"""Tests for letsencrypt.plugins.common."""
import pkg_resources
import unittest
import mock
from acme import challenges
from letsencrypt import achallenges
from letsencrypt import le_util
from letsencrypt.tests import acme_util
class NamespaceFunctionsTest(unittest.TestCase):
"""Tests for letsencrypt.plugins.common.*_namespace functions."""
@ -57,5 +65,103 @@ class PluginTest(unittest.TestCase):
"--mock-foo-bar", dest="different_to_foo_bar", x=1, y=None)
class AddrTest(unittest.TestCase):
"""Tests for letsencrypt.client.plugins.common.Addr."""
def setUp(self):
from letsencrypt.plugins.common import Addr
self.addr1 = Addr.fromstring("192.168.1.1")
self.addr2 = Addr.fromstring("192.168.1.1:*")
self.addr3 = Addr.fromstring("192.168.1.1:80")
def test_fromstring(self):
self.assertEqual(self.addr1.get_addr(), "192.168.1.1")
self.assertEqual(self.addr1.get_port(), "")
self.assertEqual(self.addr2.get_addr(), "192.168.1.1")
self.assertEqual(self.addr2.get_port(), "*")
self.assertEqual(self.addr3.get_addr(), "192.168.1.1")
self.assertEqual(self.addr3.get_port(), "80")
def test_str(self):
self.assertEqual(str(self.addr1), "192.168.1.1")
self.assertEqual(str(self.addr2), "192.168.1.1:*")
self.assertEqual(str(self.addr3), "192.168.1.1:80")
def test_get_addr_obj(self):
self.assertEqual(str(self.addr1.get_addr_obj("443")), "192.168.1.1:443")
self.assertEqual(str(self.addr2.get_addr_obj("")), "192.168.1.1")
self.assertEqual(str(self.addr1.get_addr_obj("*")), "192.168.1.1:*")
def test_eq(self):
self.assertEqual(self.addr1, self.addr2.get_addr_obj(""))
self.assertNotEqual(self.addr1, self.addr2)
self.assertFalse(self.addr1 == 3333)
def test_set_inclusion(self):
from letsencrypt.plugins.common import Addr
set_a = set([self.addr1, self.addr2])
addr1b = Addr.fromstring("192.168.1.1")
addr2b = Addr.fromstring("192.168.1.1:*")
set_b = set([addr1b, addr2b])
self.assertEqual(set_a, set_b)
class DvsniTest(unittest.TestCase):
"""Tests for letsencrypt.plugins.common.DvsniTest."""
rsa256_file = pkg_resources.resource_filename(
"acme.jose", "testdata/rsa256_key.pem")
rsa256_pem = pkg_resources.resource_string(
"acme.jose", "testdata/rsa256_key.pem")
auth_key = le_util.Key(rsa256_file, rsa256_pem)
achalls = [
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd\xeb9"
"\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4",
nonce="7\xbc^\xb7]>\x00\xa1\x9bOcU\x84^Z\x18",
), "pending"),
domain="encryption-example.demo", key=auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80"
"\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945",
nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7\xa1\xb2\xc5"
"\x96\xba",
), "pending"),
domain="letsencrypt.demo", key=auth_key),
]
def setUp(self):
from letsencrypt.plugins.common import Dvsni
self.sni = Dvsni(configurator=mock.MagicMock())
def test_setup_challenge_cert(self):
# This is a helper function that can be used for handling
# open context managers more elegantly. It avoids dealing with
# __enter__ and __exit__ calls.
# http://www.voidspace.org.uk/python/mock/helpers.html#mock.mock_open
m_open = mock.mock_open()
response = challenges.DVSNIResponse(s="randomS1")
achall = mock.MagicMock(nonce=self.achalls[0].nonce,
nonce_domain=self.achalls[0].nonce_domain)
achall.gen_cert_and_response.return_value = ("pem", response)
with mock.patch("letsencrypt.plugins.common.open", m_open, create=True):
# pylint: disable=protected-access
self.assertEqual(response, self.sni._setup_challenge_cert(
achall, "randomS1"))
self.assertTrue(m_open.called)
self.assertEqual(
m_open.call_args[0], (self.sni.get_cert_file(achall), "w"))
self.assertEqual(m_open().write.call_args[0][0], "pem")
if __name__ == "__main__":
unittest.main() # pragma: no cover

View file

@ -18,6 +18,8 @@ from letsencrypt import errors
from letsencrypt import interfaces
from letsencrypt import le_util
from letsencrypt.plugins import common
from letsencrypt_apache import constants
from letsencrypt_apache import dvsni
from letsencrypt_apache import obj
@ -230,7 +232,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return vhost
# Checking for domain name in vhost address
# This technique is not recommended by Apache but is technically valid
target_addr = obj.Addr((target_name, "443"))
target_addr = common.Addr((target_name, "443"))
for vhost in self.vhosts:
if target_addr in vhost.addrs:
self.assoc[target_name] = vhost
@ -321,7 +323,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
addrs = set()
args = self.aug.match(path + "/arg")
for arg in args:
addrs.add(obj.Addr.fromstring(self.aug.get(arg)))
addrs.add(common.Addr.fromstring(self.aug.get(arg)))
is_ssl = False
if self.parser.find_dir(
@ -486,7 +488,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
addr_match % (ssl_fp, parser.case_i("VirtualHost")))
for addr in ssl_addr_p:
old_addr = obj.Addr.fromstring(
old_addr = common.Addr.fromstring(
str(self.aug.get(addr)))
ssl_addr = old_addr.get_addr_obj("443")
self.aug.set(addr, str(ssl_addr))
@ -789,8 +791,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Instead... should look for vhost of the form *:80
# Should we prompt the user?
ssl_addrs = ssl_vhost.addrs
if ssl_addrs == obj.Addr.fromstring("_default_:443"):
ssl_addrs = [obj.Addr.fromstring("*:443")]
if ssl_addrs == common.Addr.fromstring("_default_:443"):
ssl_addrs = [common.Addr.fromstring("*:443")]
for vhost in self.vhosts:
found = 0

View file

@ -2,10 +2,12 @@
import logging
import os
from letsencrypt.plugins import common
from letsencrypt_apache import parser
class ApacheDvsni(object):
class ApacheDvsni(common.Dvsni):
"""Class performs DVSNI challenges within the Apache configurator.
:ivar configurator: ApacheConfigurator object
@ -42,26 +44,6 @@ class ApacheDvsni(object):
</VirtualHost>
"""
def __init__(self, configurator):
self.configurator = configurator
self.achalls = []
self.indices = []
self.challenge_conf = os.path.join(
configurator.config.config_dir, "le_dvsni_cert_challenge.conf")
# self.completed = 0
def add_chall(self, achall, idx=None):
"""Add challenge to DVSNI object to perform at once.
:param achall: Annotated DVSNI challenge.
:type achall: :class:`letsencrypt.achallenges.DVSNI`
:param int idx: index to challenge in a larger array
"""
self.achalls.append(achall)
if idx is not None:
self.indices.append(idx)
def perform(self):
"""Peform a DVSNI challenge."""
@ -107,28 +89,12 @@ class ApacheDvsni(object):
return responses
def _setup_challenge_cert(self, achall, s=None):
# pylint: disable=invalid-name
"""Generate and write out challenge certificate."""
cert_path = self.get_cert_file(achall)
# Register the path before you write out the file
self.configurator.reverter.register_file_creation(True, cert_path)
cert_pem, response = achall.gen_cert_and_response(s)
# Write out challenge cert
with open(cert_path, "w") as cert_chall_fd:
cert_chall_fd.write(cert_pem)
return response
def _mod_config(self, ll_addrs):
"""Modifies Apache config files to include challenge vhosts.
Result: Apache config includes virtual servers for issued challs
:param list ll_addrs: list of list of
:class:`letsencrypt.plugins.apache.obj.Addr` to apply
:param list ll_addrs: list of list of `~.common.Addr` to apply
"""
# TODO: Use ip address of existing vhost instead of relying on FQDN
@ -167,7 +133,7 @@ class ApacheDvsni(object):
:type achall: :class:`letsencrypt.achallenges.DVSNI`
:param list ip_addrs: addresses of challenged domain
:class:`list` of type :class:`~apache.obj.Addr`
:class:`list` of type `~.common.Addr`
:returns: virtual host configuration text
:rtype: str
@ -186,16 +152,3 @@ class ApacheDvsni(object):
ssl_options_conf_path=self.configurator.parser.loc["ssl_options"],
cert_path=self.get_cert_file(achall), key_path=achall.key.file,
document_root=document_root).replace("\n", os.linesep)
def get_cert_file(self, achall):
"""Returns standardized name for challenge certificate.
:param achall: Annotated DVSNI challenge.
:type achall: :class:`letsencrypt.achallenges.DVSNI`
:returns: certificate file name
:rtype: str
"""
return os.path.join(
self.configurator.config.work_dir, achall.nonce_domain + ".crt")

View file

@ -1,54 +1,13 @@
"""Module contains classes used by the Apache Configurator."""
class Addr(object):
r"""Represents an Apache VirtualHost address.
:param str addr: addr part of vhost address
:param str port: port number or \*, or ""
"""
def __init__(self, tup):
self.tup = tup
@classmethod
def fromstring(cls, str_addr):
"""Initialize Addr from string."""
tup = str_addr.partition(':')
return cls((tup[0], tup[2]))
def __str__(self):
if self.tup[1]:
return "%s:%s" % self.tup
return self.tup[0]
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.tup == other.tup
return False
def __hash__(self):
return hash(self.tup)
def get_addr(self):
"""Return addr part of Addr object."""
return self.tup[0]
def get_port(self):
"""Return port."""
return self.tup[1]
def get_addr_obj(self, port):
"""Return new address object with same addr and new port."""
return self.__class__((self.tup[0], port))
class VirtualHost(object): # pylint: disable=too-few-public-methods
"""Represents an Apache Virtualhost.
:ivar str filep: file path of VH
:ivar str path: Augeas path to virtual host
:ivar set addrs: Virtual Host addresses (:class:`set` of :class:`Addr`)
:ivar set addrs: Virtual Host addresses (:class:`set` of
:class:`common.Addr`)
:ivar set names: Server names/aliases of vhost
(:class:`list` of :class:`str`)

View file

@ -12,10 +12,11 @@ from letsencrypt import achallenges
from letsencrypt import errors
from letsencrypt import le_util
from letsencrypt.plugins import common
from letsencrypt.tests import acme_util
from letsencrypt_apache import configurator
from letsencrypt_apache import obj
from letsencrypt_apache import parser
from letsencrypt_apache.tests import util
@ -112,7 +113,7 @@ class TwoVhost80Test(util.ApacheTest):
self.vh_truth[1].filep)
def test_is_name_vhost(self):
addr = obj.Addr.fromstring("*:80")
addr = common.Addr.fromstring("*:80")
self.assertTrue(self.config.is_name_vhost(addr))
self.config.version = (2, 2)
self.assertFalse(self.config.is_name_vhost(addr))
@ -133,7 +134,7 @@ class TwoVhost80Test(util.ApacheTest):
self.assertEqual(ssl_vhost.path,
"/files" + ssl_vhost.filep + "/IfModule/VirtualHost")
self.assertEqual(len(ssl_vhost.addrs), 1)
self.assertEqual(set([obj.Addr.fromstring("*:443")]), ssl_vhost.addrs)
self.assertEqual(set([common.Addr.fromstring("*:443")]), ssl_vhost.addrs)
self.assertEqual(ssl_vhost.names, set(["encryption-example.demo"]))
self.assertTrue(ssl_vhost.ssl)
self.assertFalse(ssl_vhost.enabled)

View file

@ -1,5 +1,4 @@
"""Test for letsencrypt_apache.dvsni."""
import pkg_resources
import unittest
import shutil
@ -7,18 +6,17 @@ import mock
from acme import challenges
from letsencrypt import achallenges
from letsencrypt import le_util
from letsencrypt.plugins import common
from letsencrypt.plugins import common_test
from letsencrypt.tests import acme_util
from letsencrypt_apache import obj
from letsencrypt_apache.tests import util
class DvsniPerformTest(util.ApacheTest):
"""Test the ApacheDVSNI challenge."""
achalls = common_test.DvsniTest.achalls
def setUp(self):
super(DvsniPerformTest, self).setUp()
@ -32,32 +30,6 @@ class DvsniPerformTest(util.ApacheTest):
from letsencrypt_apache import dvsni
self.sni = dvsni.ApacheDvsni(config)
rsa256_file = pkg_resources.resource_filename(
"acme.jose", "testdata/rsa256_key.pem")
rsa256_pem = pkg_resources.resource_string(
"acme.jose", "testdata/rsa256_key.pem")
auth_key = le_util.Key(rsa256_file, rsa256_pem)
self.achalls = [
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd\xeb9"
"\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4",
nonce="7\xbc^\xb7]>\x00\xa1\x9bOcU\x84^Z\x18",
), "pending"),
domain="encryption-example.demo", key=auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80"
"\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945",
nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7\xa1\xb2\xc5"
"\x96\xba",
), "pending"),
domain="letsencrypt.demo", key=auth_key),
]
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
@ -67,28 +39,6 @@ class DvsniPerformTest(util.ApacheTest):
resp = self.sni.perform()
self.assertEqual(len(resp), 0)
def test_setup_challenge_cert(self):
# This is a helper function that can be used for handling
# open context managers more elegantly. It avoids dealing with
# __enter__ and __exit__ calls.
# http://www.voidspace.org.uk/python/mock/helpers.html#mock.mock_open
m_open = mock.mock_open()
response = challenges.DVSNIResponse(s="randomS1")
achall = mock.MagicMock(nonce=self.achalls[0].nonce,
nonce_domain=self.achalls[0].nonce_domain)
achall.gen_cert_and_response.return_value = ("pem", response)
with mock.patch("letsencrypt_apache.dvsni.open", m_open, create=True):
# pylint: disable=protected-access
self.assertEqual(response, self.sni._setup_challenge_cert(
achall, "randomS1"))
self.assertTrue(m_open.called)
self.assertEqual(
m_open.call_args[0], (self.sni.get_cert_file(achall), "w"))
self.assertEqual(m_open().write.call_args[0][0], "pem")
def test_perform1(self):
achall = self.achalls[0]
self.sni.add_chall(achall)
@ -140,8 +90,9 @@ class DvsniPerformTest(util.ApacheTest):
def test_mod_config(self):
for achall in self.achalls:
self.sni.add_chall(achall)
v_addr1 = [obj.Addr(("1.2.3.4", "443")), obj.Addr(("5.6.7.8", "443"))]
v_addr2 = [obj.Addr(("127.0.0.1", "443"))]
v_addr1 = [common.Addr(("1.2.3.4", "443")),
common.Addr(("5.6.7.8", "443"))]
v_addr2 = [common.Addr(("127.0.0.1", "443"))]
ll_addr = []
ll_addr.append(v_addr1)
ll_addr.append(v_addr2)

View file

@ -1,63 +1,23 @@
"""Test the helper objects in letsencrypt_apache.obj."""
"""Tests for letsencrypt_apache.obj."""
import unittest
class AddrTest(unittest.TestCase):
"""Test the Addr class."""
def setUp(self):
from letsencrypt_apache.obj import Addr
self.addr1 = Addr.fromstring("192.168.1.1")
self.addr2 = Addr.fromstring("192.168.1.1:*")
self.addr3 = Addr.fromstring("192.168.1.1:80")
def test_fromstring(self):
self.assertEqual(self.addr1.get_addr(), "192.168.1.1")
self.assertEqual(self.addr1.get_port(), "")
self.assertEqual(self.addr2.get_addr(), "192.168.1.1")
self.assertEqual(self.addr2.get_port(), "*")
self.assertEqual(self.addr3.get_addr(), "192.168.1.1")
self.assertEqual(self.addr3.get_port(), "80")
def test_str(self):
self.assertEqual(str(self.addr1), "192.168.1.1")
self.assertEqual(str(self.addr2), "192.168.1.1:*")
self.assertEqual(str(self.addr3), "192.168.1.1:80")
def test_get_addr_obj(self):
self.assertEqual(str(self.addr1.get_addr_obj("443")), "192.168.1.1:443")
self.assertEqual(str(self.addr2.get_addr_obj("")), "192.168.1.1")
self.assertEqual(str(self.addr1.get_addr_obj("*")), "192.168.1.1:*")
def test_eq(self):
self.assertEqual(self.addr1, self.addr2.get_addr_obj(""))
self.assertNotEqual(self.addr1, self.addr2)
self.assertFalse(self.addr1 == 3333)
def test_set_inclusion(self):
from letsencrypt_apache.obj import Addr
set_a = set([self.addr1, self.addr2])
addr1b = Addr.fromstring("192.168.1.1")
addr2b = Addr.fromstring("192.168.1.1:*")
set_b = set([addr1b, addr2b])
self.assertEqual(set_a, set_b)
from letsencrypt.plugins import common
class VirtualHostTest(unittest.TestCase):
"""Test the VirtualHost class."""
def setUp(self):
from letsencrypt_apache.obj import VirtualHost
from letsencrypt_apache.obj import Addr
self.vhost1 = VirtualHost(
"filep", "vh_path",
set([Addr.fromstring("localhost")]), False, False)
set([common.Addr.fromstring("localhost")]), False, False)
def test_eq(self):
from letsencrypt_apache.obj import Addr
from letsencrypt_apache.obj import VirtualHost
vhost1b = VirtualHost(
"filep", "vh_path",
set([Addr.fromstring("localhost")]), False, False)
set([common.Addr.fromstring("localhost")]), False, False)
self.assertEqual(vhost1b, self.vhost1)
self.assertEqual(str(vhost1b), str(self.vhost1))

View file

@ -1,13 +1,11 @@
"""Common utilities for letsencrypt_apache."""
import os
import pkg_resources
import shutil
import tempfile
import unittest
import mock
from letsencrypt import constants as core_constants
from letsencrypt.plugins import common
from letsencrypt_apache import configurator
from letsencrypt_apache import constants
@ -19,10 +17,12 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
def setUp(self):
super(ApacheTest, self).setUp()
self.temp_dir, self.config_dir, self.work_dir = dir_setup(
"debian_apache_2_4/two_vhost_80")
self.temp_dir, self.config_dir, self.work_dir = common.dir_setup(
test_dir="debian_apache_2_4/two_vhost_80",
pkg="letsencrypt_apache.tests")
self.ssl_options = setup_ssl_options(self.config_dir)
self.ssl_options = common.setup_ssl_options(
self.config_dir, constants.MOD_SSL_CONF)
self.config_path = os.path.join(
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2")
@ -33,34 +33,6 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
"acme.jose", "testdata/rsa256_key.pem")
def dir_setup(test_dir="debian_apache_2_4/two_vhost_80",
pkg="letsencrypt_apache.tests"):
"""Setup the directories necessary for the configurator."""
temp_dir = tempfile.mkdtemp("temp")
config_dir = tempfile.mkdtemp("config")
work_dir = tempfile.mkdtemp("work")
os.chmod(temp_dir, core_constants.CONFIG_DIRS_MODE)
os.chmod(config_dir, core_constants.CONFIG_DIRS_MODE)
os.chmod(work_dir, core_constants.CONFIG_DIRS_MODE)
test_configs = pkg_resources.resource_filename(
pkg, os.path.join("testdata", test_dir))
shutil.copytree(
test_configs, os.path.join(temp_dir, test_dir), symlinks=True)
return temp_dir, config_dir, work_dir
def setup_ssl_options(
config_dir, mod_ssl_conf=constants.MOD_SSL_CONF):
"""Move the ssl_options into position and return the path."""
option_path = os.path.join(config_dir, "options-ssl.conf")
shutil.copyfile(mod_ssl_conf, option_path)
return option_path
def get_apache_configurator(
config_path, config_dir, work_dir, ssl_options, version=(2, 4, 7)):
"""Create an Apache Configurator with the specified options."""
@ -99,21 +71,21 @@ def get_vh_truth(temp_dir, config_name):
obj.VirtualHost(
os.path.join(prefix, "encryption-example.conf"),
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]),
set([common.Addr.fromstring("*:80")]),
False, True, set(["encryption-example.demo"])),
obj.VirtualHost(
os.path.join(prefix, "default-ssl.conf"),
os.path.join(aug_pre, "default-ssl.conf/IfModule/VirtualHost"),
set([obj.Addr.fromstring("_default_:443")]), True, False),
set([common.Addr.fromstring("_default_:443")]), True, False),
obj.VirtualHost(
os.path.join(prefix, "000-default.conf"),
os.path.join(aug_pre, "000-default.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set([common.Addr.fromstring("*:80")]), False, True,
set(["ip-172-30-0-17"])),
obj.VirtualHost(
os.path.join(prefix, "letsencrypt.conf"),
os.path.join(aug_pre, "letsencrypt.conf/VirtualHost"),
set([obj.Addr.fromstring("*:80")]), False, True,
set([common.Addr.fromstring("*:80")]), False, True,
set(["letsencrypt.demo"])),
]
return vh_truth

View file

@ -4,14 +4,13 @@ import logging
import os
from letsencrypt import errors
from letsencrypt_apache.dvsni import ApacheDvsni
from letsencrypt.plugins import common
from letsencrypt_nginx import obj
from letsencrypt_nginx import nginxparser
class NginxDvsni(ApacheDvsni):
class NginxDvsni(common.Dvsni):
"""Class performs DVSNI challenges within the Nginx configurator.
:ivar configurator: NginxConfigurator object

View file

@ -1,10 +1,10 @@
"""Module contains classes used by the Nginx Configurator."""
import re
from letsencrypt_apache.obj import Addr as ApacheAddr
from letsencrypt.plugins import common
class Addr(ApacheAddr):
class Addr(common.Addr):
r"""Represents an Nginx address, i.e. what comes after the 'listen'
directive.

View file

@ -1,5 +1,4 @@
"""Test for letsencrypt_nginx.dvsni."""
import pkg_resources
import unittest
import shutil
@ -9,7 +8,8 @@ from acme import challenges
from letsencrypt import achallenges
from letsencrypt import errors
from letsencrypt import le_util
from letsencrypt.plugins import common_test
from letsencrypt.tests import acme_util
from letsencrypt_nginx import obj
@ -19,6 +19,34 @@ from letsencrypt_nginx.tests import util
class DvsniPerformTest(util.NginxTest):
"""Test the NginxDVSNI challenge."""
achalls = [
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="foo",
nonce="bar"
), "pending"),
domain="www.example.com", key=common_test.DvsniTest.auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80"
"\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945",
nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7"
"\xa1\xb2\xc5\x96\xba"
), "pending"),
domain="blah", key=common_test.DvsniTest.auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd\xeb9"
"\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4",
nonce="7\xbc^\xb7]>\x00\xa1\x9bOcU\x84^Z\x18"
), "pending"),
domain="www.example.org", key=common_test.DvsniTest.auth_key)
]
def setUp(self):
super(DvsniPerformTest, self).setUp()
@ -26,43 +54,9 @@ class DvsniPerformTest(util.NginxTest):
self.config_path, self.config_dir, self.work_dir,
self.ssl_options)
rsa256_file = pkg_resources.resource_filename(
"acme.jose", "testdata/rsa256_key.pem")
rsa256_pem = pkg_resources.resource_string(
"acme.jose", "testdata/rsa256_key.pem")
auth_key = le_util.Key(rsa256_file, rsa256_pem)
from letsencrypt_nginx import dvsni
self.sni = dvsni.NginxDvsni(config)
self.achalls = [
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="foo",
nonce="bar"
), "pending"),
domain="www.example.com", key=auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y\x80"
"\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945",
nonce="Y\xed\x01L\xac\x95\xf7pW\xb1\xd7"
"\xa1\xb2\xc5\x96\xba"
), "pending"),
domain="blah", key=auth_key),
achallenges.DVSNI(
challb=acme_util.chall_to_challb(
challenges.DVSNI(
r="\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd\xeb9"
"\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4",
nonce="7\xbc^\xb7]>\x00\xa1\x9bOcU\x84^Z\x18"
), "pending"),
domain="www.example.org", key=auth_key)
]
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)

View file

@ -5,7 +5,7 @@ import unittest
import mock
from letsencrypt_apache.tests import util as apache_util
from letsencrypt.plugins import common
from letsencrypt_nginx import constants
from letsencrypt_nginx import configurator
@ -16,10 +16,10 @@ class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods
def setUp(self):
super(NginxTest, self).setUp()
self.temp_dir, self.config_dir, self.work_dir = apache_util.dir_setup(
self.temp_dir, self.config_dir, self.work_dir = common.dir_setup(
"etc_nginx", "letsencrypt_nginx.tests")
self.ssl_options = apache_util.setup_ssl_options(
self.ssl_options = common.setup_ssl_options(
self.config_dir, constants.MOD_SSL_CONF)
self.config_path = os.path.join(self.temp_dir, "etc_nginx")

View file

@ -21,4 +21,4 @@ rm -f .coverage # --cover-erase is off, make sure stats are correct
# 0, coveralls submit will be triggered (c.f. .travis.yml,
# after_success)
cover letsencrypt 95 && cover acme 100 && \
cover letsencrypt_apache 78 && cover letsencrypt_nginx 96
cover letsencrypt_apache 76 && cover letsencrypt_nginx 96