mirror of
https://github.com/certbot/certbot.git
synced 2026-05-28 04:34:11 -04:00
Refactored/added tests
This commit is contained in:
parent
083024cb86
commit
cc999d3654
14 changed files with 362 additions and 201 deletions
|
|
@ -67,7 +67,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
with the configuration
|
||||
:ivar float version: version of Apache
|
||||
:ivar list vhosts: All vhosts found in the configuration
|
||||
(:class:`list` of :class:`letsencrypt.client.apache.obj.VH`)
|
||||
(:class:`list` of :class:`letsencrypt.client.apache.obj.VirtualHost`)
|
||||
|
||||
:ivar dict assoc: Mapping between domains and vhosts
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
super(ApacheConfigurator, self).__init__(direc)
|
||||
|
||||
# See if any temporary changes need to be recovered
|
||||
# This needs to occur before VH objects are setup...
|
||||
# This needs to occur before VirtualHost objects are setup...
|
||||
# because this will change the underlying configuration and potential
|
||||
# vhosts
|
||||
self.recovery_routine()
|
||||
|
|
@ -145,7 +145,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
This shouldn't happen within letsencrypt though
|
||||
|
||||
:param vhost: ssl vhost to deploy certificate
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:param str cert: certificate filename
|
||||
:param str key: private key filename
|
||||
|
|
@ -204,7 +204,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
:param str name: domain name
|
||||
|
||||
:returns: ssl vhost associated with name
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
# Allows for domain names to be associated with a virtual host
|
||||
|
|
@ -242,7 +242,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
:param str domain: domain name to associate
|
||||
|
||||
:param vhost: virtual host to associate with domain
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
self.assoc[domain] = vhost
|
||||
|
|
@ -279,7 +279,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
"""Helper function for get_virtual_hosts().
|
||||
|
||||
:param host: In progress vhost whose names will be added
|
||||
:type host: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type host: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
name_match = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
|
||||
|
|
@ -300,7 +300,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
:param str path: Augeas path to virtual host
|
||||
|
||||
:returns: newly created vhost
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
addrs = set()
|
||||
|
|
@ -315,7 +315,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
|
||||
filename = get_file_path(path)
|
||||
is_enabled = self.is_site_enabled(filename)
|
||||
vhost = obj.VH(filename, path, addrs, is_ssl, is_enabled)
|
||||
vhost = obj.VirtualHost(filename, path, addrs, is_ssl, is_enabled)
|
||||
self._add_servernames(vhost)
|
||||
return vhost
|
||||
|
||||
|
|
@ -323,7 +323,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
def get_virtual_hosts(self):
|
||||
"""Returns list of virtual hosts found in the Apache configuration.
|
||||
|
||||
:returns: List of :class:`letsencrypt.client.apache.obj.VH` objects
|
||||
:returns: List of
|
||||
:class:`letsencrypt.client.apache.obj.VirtualHost` objects
|
||||
found in configuration
|
||||
:rtype: list
|
||||
|
||||
|
|
@ -400,8 +401,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
def make_server_sni_ready(self, vhost, default_addr="*:443"):
|
||||
"""Checks to see if the server is ready for SNI challenges.
|
||||
|
||||
:param vhost: VHost to check SNI compatibility
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:param vhost: VirtualHostost to check SNI compatibility
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:param str default_addr: TODO - investigate function further
|
||||
|
||||
|
|
@ -431,10 +432,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT
|
||||
|
||||
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
|
||||
:type nonssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type nonssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: SSL vhost
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
avail_fp = nonssl_vhost.filep
|
||||
|
|
@ -472,11 +473,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
addr_match % (ssl_fp, parser.case_i('VirtualHost')))
|
||||
|
||||
for i in range(len(ssl_addr_p)):
|
||||
ssl_addr_arg = obj.Addr.fromstring(
|
||||
old_addr = obj.Addr.fromstring(
|
||||
str(self.aug.get(ssl_addr_p[i])))
|
||||
ssl_addr_arg.set_port("443")
|
||||
self.aug.set(ssl_addr_p[i], str(ssl_addr_arg))
|
||||
ssl_addrs.add(ssl_addr_arg)
|
||||
ssl_addr = old_addr.get_addr_obj("443")
|
||||
self.aug.set(ssl_addr_p[i], str(ssl_addr))
|
||||
ssl_addrs.add(ssl_addr)
|
||||
|
||||
# Add directives
|
||||
vh_p = self.aug.match(("/files%s//* [label()=~regexp('%s')]" %
|
||||
|
|
@ -528,10 +529,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
The function then adds the directive
|
||||
|
||||
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: Success, general_vhost (HTTP vhost)
|
||||
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VH`)
|
||||
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
|
||||
|
||||
"""
|
||||
# TODO: Enable check to see if it is already there
|
||||
|
|
@ -577,7 +578,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
-1 is also returned in case of no redirection/rewrite directives
|
||||
|
||||
:param vhost: vhost to check
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: Success, code value... see documentation
|
||||
:rtype: bool, int
|
||||
|
|
@ -608,10 +609,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
|
||||
|
||||
:param ssl_vhost: ssl vhost
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: Success, vhost
|
||||
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VH`)
|
||||
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
|
||||
|
||||
"""
|
||||
# Consider changing this to a dictionary check
|
||||
|
|
@ -694,7 +695,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
if not conflict: returns space separated list of new host addrs
|
||||
|
||||
:param ssl_vhost: SSL Vhost to check for possible port 80 redirection
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: TODO
|
||||
:rtype: TODO
|
||||
|
|
@ -727,10 +728,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
Consider changing this into a dict check
|
||||
|
||||
:param ssl_vhost: ssl vhost to check
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: HTTP vhost or None if unsuccessful
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VH` or None
|
||||
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost` or None
|
||||
|
||||
"""
|
||||
# _default_:443 check
|
||||
|
|
@ -826,7 +827,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
.. todo:: Make sure link is not broken...
|
||||
|
||||
:param vhost: vhost to enable
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VH`
|
||||
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
|
||||
|
||||
:returns: Success
|
||||
:rtype: bool
|
||||
|
|
@ -1048,11 +1049,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
shutil.copyfile(dist_conf, CONFIG.OPTIONS_SSL_CONF)
|
||||
|
||||
# TODO: Use ip address of existing vhost instead of relying on FQDN
|
||||
config_text = "<IfModule mod_ssl.c> \n"
|
||||
config_text = "<IfModule mod_ssl.c>\n"
|
||||
for idx, lis in enumerate(ll_addrs):
|
||||
config_text += self.get_config_text(
|
||||
list_sni_tuple[idx][2], lis, dvsni_key.file)
|
||||
config_text += "</IfModule> \n"
|
||||
config_text += "</IfModule>\n"
|
||||
|
||||
self.dvsni_conf_include_check(self.parser.loc["default"])
|
||||
self.register_file_creation(True, CONFIG.APACHE_CHALLENGE_CONF)
|
||||
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
|
||||
class Addr(object):
|
||||
"""Represents an Apache VirtualHost address."""
|
||||
def __init__(self, addr):
|
||||
""":param tuple addr: tuple of strings (ip, port)"""
|
||||
self.tup = addr
|
||||
"""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):
|
||||
|
|
@ -14,25 +18,18 @@ class Addr(object):
|
|||
return cls((tup[0], tup[2]))
|
||||
|
||||
def __str__(self):
|
||||
if self.tup[1] != "":
|
||||
return ':'.join(self.tup)
|
||||
return str(self.tup[0])
|
||||
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
|
||||
if type(other) is type(self):
|
||||
return self.__dict__ == other.__dict__
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.tup)
|
||||
|
||||
def set_port(self, port):
|
||||
"""Set the port of the address.
|
||||
|
||||
:param str port: new port
|
||||
"""
|
||||
self.tup = (self.tup[0], port)
|
||||
|
||||
def get_addr(self):
|
||||
"""Return addr part of Addr object."""
|
||||
return self.tup[0]
|
||||
|
|
@ -47,7 +44,7 @@ class Addr(object):
|
|||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class VH(object):
|
||||
class VirtualHost(object):
|
||||
"""Represents an Apache Virtualhost.
|
||||
|
||||
:ivar str filep: file path of VH
|
||||
|
|
@ -66,7 +63,7 @@ class VH(object):
|
|||
self.filep = filep
|
||||
self.path = path
|
||||
self.addrs = addrs
|
||||
self.names = set() if names is None else names
|
||||
self.names = set() if names is None else set(names)
|
||||
self.ssl = ssl
|
||||
self.enabled = enabled
|
||||
|
||||
|
|
@ -75,12 +72,13 @@ class VH(object):
|
|||
self.names.add(name)
|
||||
|
||||
def __str__(self):
|
||||
addr_str = ", ".join(str(addr) for addr in self.addrs)
|
||||
return ("file: %s\n"
|
||||
"vh_path: %s\n"
|
||||
"addrs: %s\n"
|
||||
"names: %s\n"
|
||||
"ssl: %s\n"
|
||||
"enabled: %s" % (self.filep, self.path, self.addrs,
|
||||
"enabled: %s" % (self.filep, self.path, addr_str,
|
||||
self.names, self.ssl, self.enabled))
|
||||
|
||||
def __eq__(self, other):
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
from letsencrypt.client import errors
|
||||
|
||||
|
||||
class ApacheParser(object):
|
||||
"""Class handles the fine details of parsing the Apache Configuration."""
|
||||
|
|
@ -311,7 +313,7 @@ class ApacheParser(object):
|
|||
|
||||
"""
|
||||
root = self._find_config_root()
|
||||
default = self._set_user_config_file()
|
||||
default = self._set_user_config_file(root)
|
||||
|
||||
temp = os.path.join(self.root, "ports.conf")
|
||||
if os.path.isfile(temp):
|
||||
|
|
@ -335,7 +337,7 @@ class ApacheParser(object):
|
|||
raise errors.LetsEncryptConfiguratorError(
|
||||
"Could not find configuration root")
|
||||
|
||||
def _set_user_config_file(self, filename=''):
|
||||
def _set_user_config_file(self, root):
|
||||
"""Set the appropriate user configuration file
|
||||
|
||||
.. todo:: This will have to be updated for other distros versions
|
||||
|
|
@ -344,18 +346,15 @@ class ApacheParser(object):
|
|||
user config
|
||||
|
||||
"""
|
||||
if filename:
|
||||
return filename
|
||||
# Basic check to see if httpd.conf exists and
|
||||
# in heirarchy via direct include
|
||||
# httpd.conf was very common as a user file in Apache 2.2
|
||||
if (os.path.isfile(self.root + 'httpd.conf') and
|
||||
self.find_dir(
|
||||
case_i("Include"), case_i("httpd.conf"), root)):
|
||||
return os.path.join(self.root, 'httpd.conf')
|
||||
else:
|
||||
# Basic check to see if httpd.conf exists and
|
||||
# in heirarchy via direct include
|
||||
# httpd.conf was very common as a user file in Apache 2.2
|
||||
if (os.path.isfile(self.root + 'httpd.conf') and
|
||||
self.find_dir(
|
||||
case_i("Include"), case_i("httpd.conf"))):
|
||||
return os.path.join(self.root, 'httpd.conf')
|
||||
else:
|
||||
return os.path.join(self.root + 'apache2.conf')
|
||||
return os.path.join(self.root + 'apache2.conf')
|
||||
|
||||
|
||||
def case_i(string):
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ class AugeasConfigurator(object):
|
|||
(used mostly for testing)
|
||||
|
||||
"""
|
||||
super(AugeasConfigurator, self).__init__()
|
||||
|
||||
if not direc:
|
||||
direc = {"backup": CONFIG.BACKUP_DIR,
|
||||
|
|
|
|||
|
|
@ -59,18 +59,13 @@ class Client(object):
|
|||
self.auth = auth
|
||||
self.installer = installer
|
||||
|
||||
def obtain_certificate(self, privkey, csr,
|
||||
def obtain_certificate(self, csr,
|
||||
cert_path=CONFIG.CERT_PATH,
|
||||
chain_path=CONFIG.CHAIN_PATH):
|
||||
"""Obtains a certificate from the ACME server.
|
||||
|
||||
.. todo:: Check for case when privkey is not authkey and adjust
|
||||
this function accordingly.
|
||||
|
||||
:param privkey: A valid private key that corresponds to the csr
|
||||
:type privkey: :class:`Key`
|
||||
|
||||
:param csr: A valid CSR in der format that corresponds to privkey
|
||||
:param csr: A valid CSR in DER format for the certificate the client
|
||||
intends to receive.
|
||||
:type csr: :class:`CSR`
|
||||
|
||||
:param str cert_path: Full desired path to end certificate.
|
||||
|
|
@ -699,8 +694,7 @@ def init_key():
|
|||
def init_csr(privkey, names):
|
||||
"""Initialize a CSR with the given private key."""
|
||||
|
||||
csr_pem, csr_der = crypto_util.make_csr(
|
||||
privkey.pem, names)
|
||||
csr_pem, csr_der = crypto_util.make_csr(privkey.pem, names)
|
||||
|
||||
# Save CSR
|
||||
le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0o755)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ def sha256(arg):
|
|||
# based on M2Crypto unit test written by Toby Allsopp
|
||||
def make_key(bits=CONFIG.RSA_KEY_SIZE):
|
||||
"""Returns new RSA key in PEM form with specified bits."""
|
||||
|
||||
# Python Crypto module doesn't produce any stdout
|
||||
key = Crypto.PublicKey.RSA.generate(bits)
|
||||
# rsa = M2Crypto.RSA.gen_key(bits, 65537)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
"""Interfaces."""
|
||||
|
||||
import zope.interface
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,19 @@
|
|||
"""Test for letsencrypt.client.apache_configurator."""
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
|
||||
from letsencrypt.client import apache_configurator
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
|
||||
from letsencrypt.client.apache import configurator
|
||||
from letsencrypt.client.apache import obj
|
||||
from letsencrypt.client.apache import parser
|
||||
|
||||
UBUNTU_CONFIGS = pkg_resources.resource_filename(
|
||||
__name__, "testdata/debian_apache_2_4")
|
||||
from letsencrypt.client.tests import config_util
|
||||
|
||||
|
||||
class TwoVhost80Test(unittest.TestCase):
|
||||
|
|
@ -25,102 +22,31 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
def setUp(self):
|
||||
display.set_display(display.NcursesDisplay())
|
||||
|
||||
self.temp_dir = os.path.join(
|
||||
tempfile.mkdtemp("temp"), "debian_apache_2_4")
|
||||
self.config_dir = tempfile.mkdtemp("config")
|
||||
self.work_dir = tempfile.mkdtemp("work")
|
||||
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
|
||||
"debian_apache_2_4/two_vhost_80")
|
||||
|
||||
shutil.copytree(UBUNTU_CONFIGS, self.temp_dir, symlinks=True)
|
||||
|
||||
temp_options = pkg_resources.resource_filename(
|
||||
"letsencrypt.client", os.path.basename(CONFIG.OPTIONS_SSL_CONF))
|
||||
shutil.copyfile(
|
||||
temp_options, os.path.join(self.config_dir, "options-ssl.conf"))
|
||||
self.ssl_options = config_util.setup_apache_ssl_options(self.config_dir)
|
||||
|
||||
# Final slash is currently important
|
||||
self.config_path = os.path.join(self.temp_dir, "two_vhost_80/apache2/")
|
||||
self.ssl_options = os.path.join(self.config_dir, "options-ssl.conf")
|
||||
backups = os.path.join(self.work_dir, "backups")
|
||||
self.config_path = os.path.join(
|
||||
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2/")
|
||||
|
||||
with mock.patch("letsencrypt.client.apache_configurator."
|
||||
"subprocess.Popen") as mock_popen:
|
||||
# This just states that the ssl module is already loaded
|
||||
mock_popen().communicate.return_value = ("ssl_module", "")
|
||||
self.config = apache_configurator.ApacheConfigurator(
|
||||
self.config_path,
|
||||
{
|
||||
"backup": backups,
|
||||
"temp": os.path.join(self.work_dir, "temp_checkpoint"),
|
||||
"progress": os.path.join(backups, "IN_PROGRESS"),
|
||||
"config": self.config_dir,
|
||||
"work": self.work_dir,
|
||||
},
|
||||
self.ssl_options,
|
||||
(2, 4, 7))
|
||||
self.config = config_util.get_apache_configurator(
|
||||
self.config_path, self.config_dir, self.work_dir, self.ssl_options)
|
||||
|
||||
prefix = os.path.join(
|
||||
self.temp_dir, "two_vhost_80/apache2/sites-available")
|
||||
aug_pre = "/files" + prefix
|
||||
self.vh_truth = [
|
||||
obj.VH(
|
||||
os.path.join(prefix, "encryption-example.conf"),
|
||||
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
|
||||
set([obj.Addr.fromstring("*:80")]),
|
||||
False, True, set(["encryption-example.demo"])),
|
||||
obj.VH(
|
||||
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),
|
||||
obj.VH(
|
||||
os.path.join(prefix, "000-default.conf"),
|
||||
os.path.join(aug_pre, "000-default.conf/VirtualHost"),
|
||||
set([obj.Addr.fromstring("*:80")]), False, True,
|
||||
set(["ip-172-30-0-17"])),
|
||||
obj.VH(
|
||||
os.path.join(prefix, "letsencrypt.conf"),
|
||||
os.path.join(aug_pre, "letsencrypt.conf/VirtualHost"),
|
||||
set([obj.Addr.fromstring("*:80")]), False, True,
|
||||
set(["letsencrypt.demo"])),
|
||||
]
|
||||
self.vh_truth = config_util.get_vh_truth(
|
||||
self.temp_dir, "debian_apache_2_4/two_vhost_80")
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.temp_dir)
|
||||
shutil.rmtree(self.config_dir)
|
||||
shutil.rmtree(self.work_dir)
|
||||
|
||||
def test_parse_file(self):
|
||||
"""Test parse_file.
|
||||
|
||||
letsencrypt.conf is chosen as the test file as it will not be
|
||||
included during the normal course of execution.
|
||||
|
||||
"""
|
||||
file_path = os.path.join(
|
||||
self.config_path, "sites-available", "letsencrypt.conf")
|
||||
|
||||
# pylint: disable=protected-access
|
||||
self.config.parser._parse_file(file_path)
|
||||
|
||||
# search for the httpd incl
|
||||
matches = self.config.aug.match(
|
||||
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
|
||||
|
||||
self.assertTrue(matches)
|
||||
|
||||
def test_get_all_names(self):
|
||||
names = self.config.get_all_names()
|
||||
self.assertEqual(names, set(
|
||||
['letsencrypt.demo', 'encryption-example.demo', 'ip-172-30-0-17']))
|
||||
|
||||
def test_find_dir(self):
|
||||
test = self.config.parser.find_dir(
|
||||
parser.case_i("Listen"), "443")
|
||||
# This will only look in enabled hosts
|
||||
test2 = self.config.parser.find_dir(
|
||||
parser.case_i("documentroot"))
|
||||
self.assertEqual(len(test), 2)
|
||||
self.assertEqual(len(test2), 3)
|
||||
|
||||
def test_get_virtual_hosts(self):
|
||||
vhs = self.config.get_virtual_hosts()
|
||||
self.assertEqual(len(vhs), 4)
|
||||
|
|
@ -140,14 +66,6 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
self.assertTrue(self.config.is_site_enabled(self.vh_truth[2].filep))
|
||||
self.assertTrue(self.config.is_site_enabled(self.vh_truth[3].filep))
|
||||
|
||||
def test_add_dir(self):
|
||||
aug_default = "/files" + self.config.parser.loc["default"]
|
||||
self.config.parser.add_dir(
|
||||
aug_default, "AddDirective", "test")
|
||||
|
||||
self.assertTrue(
|
||||
self.config.parser.find_dir("AddDirective", "test", aug_default))
|
||||
|
||||
def test_deploy_cert(self):
|
||||
self.config.deploy_cert(
|
||||
self.vh_truth[1],
|
||||
|
|
@ -165,15 +83,15 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
|
||||
# Verify one directive was found in the correct file
|
||||
self.assertEqual(len(loc_cert), 1)
|
||||
self.assertEqual(apache_configurator.get_file_path(loc_cert[0]),
|
||||
self.assertEqual(configurator.get_file_path(loc_cert[0]),
|
||||
self.vh_truth[1].filep)
|
||||
|
||||
self.assertEqual(len(loc_key), 1)
|
||||
self.assertEqual(apache_configurator.get_file_path(loc_key[0]),
|
||||
self.assertEqual(configurator.get_file_path(loc_key[0]),
|
||||
self.vh_truth[1].filep)
|
||||
|
||||
self.assertEqual(len(loc_chain), 1)
|
||||
self.assertEqual(apache_configurator.get_file_path(loc_chain[0]),
|
||||
self.assertEqual(configurator.get_file_path(loc_chain[0]),
|
||||
self.vh_truth[1].filep)
|
||||
|
||||
def test_is_name_vhost(self):
|
||||
|
|
@ -187,21 +105,6 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
self.assertTrue(self.config.parser.find_dir(
|
||||
"NameVirtualHost", re.escape("*:443")))
|
||||
|
||||
def test_add_dir_to_ifmodssl(self):
|
||||
"""test add_dir_to_ifmodssl.
|
||||
|
||||
Path must be valid before attempting to add to augeas
|
||||
|
||||
"""
|
||||
self.config.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(self.config.parser.loc["default"]),
|
||||
"FakeDirective", "123")
|
||||
|
||||
matches = self.config.parser.find_dir("FakeDirective", "123")
|
||||
|
||||
self.assertEqual(len(matches), 1)
|
||||
self.assertTrue("IfModule" in matches[0])
|
||||
|
||||
def test_make_vhost_ssl(self):
|
||||
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
||||
|
||||
|
|
@ -212,7 +115,8 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
|
||||
self.assertEqual(ssl_vhost.path,
|
||||
"/files" + ssl_vhost.filep + "/IfModule/VirtualHost")
|
||||
self.assertEqual(ssl_vhost.addrs, set([obj.Addr.fromstring("*:443")]))
|
||||
self.assertEqual(len(ssl_vhost.addrs), 1)
|
||||
self.assertTrue(set([obj.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)
|
||||
|
|
@ -229,7 +133,7 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
|
||||
self.assertEqual(len(self.config.vhosts), 5)
|
||||
|
||||
@mock.patch("letsencrypt.client.apache_configurator."
|
||||
@mock.patch("letsencrypt.client.apache.configurator."
|
||||
"subprocess.Popen")
|
||||
def test_get_version(self, mock_popen):
|
||||
mock_popen().communicate.return_value = (
|
||||
|
|
@ -254,6 +158,5 @@ class TwoVhost80Test(unittest.TestCase):
|
|||
self.assertRaises(
|
||||
errors.LetsEncryptConfiguratorError, self.config.get_version)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
|||
62
letsencrypt/client/tests/apache_obj_test.py
Normal file
62
letsencrypt/client/tests/apache_obj_test.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import unittest
|
||||
|
||||
from letsencrypt.client.apache import obj
|
||||
|
||||
|
||||
class AddrTest(unittest.TestCase):
|
||||
"""Test the Addr class."""
|
||||
def setUp(self):
|
||||
self.addr1 = obj.Addr.fromstring("192.168.1.1")
|
||||
self.addr2 = obj.Addr.fromstring("192.168.1.1:*")
|
||||
self.addr3 = obj.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)
|
||||
# This is specifically designed to hit line 28 but coverage denies me
|
||||
# the satisfaction :(
|
||||
self.assertNotEqual(self.addr1, 3333)
|
||||
|
||||
def test_set_inclusion(self):
|
||||
set_a = set([self.addr1, self.addr2])
|
||||
addr1b = obj.Addr.fromstring("192.168.1.1")
|
||||
addr2b = obj.Addr.fromstring("192.168.1.1:*")
|
||||
set_b = set([addr1b, addr2b])
|
||||
|
||||
self.assertTrue(addr1b in set_a)
|
||||
self.assertEqual(set_a, set_b)
|
||||
|
||||
|
||||
class VirtualHostTest(unittest.TestCase):
|
||||
"""Test the VirtualHost class."""
|
||||
def setUp(self):
|
||||
self.vhost1 = obj.VirtualHost(
|
||||
"filep", "vh_path",
|
||||
set([obj.Addr.fromstring("localhost")]), False, False)
|
||||
|
||||
def test_eq(self):
|
||||
vhost1b = obj.VirtualHost(
|
||||
"filep", "vh_path",
|
||||
set([obj.Addr.fromstring("localhost")]), False, False)
|
||||
|
||||
self.assertEqual(vhost1b, self.vhost1)
|
||||
self.assertEqual(str(vhost1b), str(self.vhost1))
|
||||
self.assertTrue(vhost1b != 1234)
|
||||
114
letsencrypt/client/tests/apache_parser_test.py
Normal file
114
letsencrypt/client/tests/apache_parser_test.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import augeas
|
||||
import mock
|
||||
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
from letsencrypt.client.apache import parser
|
||||
from letsencrypt.client.tests import config_util
|
||||
|
||||
|
||||
class BasicParseTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
display.set_display(display.FileDisplay(sys.stdout))
|
||||
|
||||
self.temp_dir, self.config_dir, self.work_dir = config_util.dir_setup(
|
||||
"debian_apache_2_4/two_vhost_80")
|
||||
|
||||
self.ssl_options = config_util.setup_apache_ssl_options(self.config_dir)
|
||||
|
||||
# Final slash is currently important
|
||||
self.config_path = os.path.join(
|
||||
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2/")
|
||||
|
||||
self.parser = parser.ApacheParser(
|
||||
augeas.Augeas(flags=augeas.Augeas.NONE),
|
||||
self.config_path, self.ssl_options)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.temp_dir)
|
||||
shutil.rmtree(self.config_dir)
|
||||
shutil.rmtree(self.work_dir)
|
||||
|
||||
def test_parse_file(self):
|
||||
"""Test parse_file.
|
||||
|
||||
letsencrypt.conf is chosen as the test file as it will not be
|
||||
included during the normal course of execution.
|
||||
|
||||
"""
|
||||
file_path = os.path.join(
|
||||
self.config_path, "sites-available", "letsencrypt.conf")
|
||||
|
||||
# pylint: disable=protected-access
|
||||
self.parser._parse_file(file_path)
|
||||
|
||||
# search for the httpd incl
|
||||
matches = self.parser.aug.match(
|
||||
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
|
||||
|
||||
self.assertTrue(matches)
|
||||
|
||||
def test_find_dir(self):
|
||||
test = self.parser.find_dir(
|
||||
parser.case_i("Listen"), "443")
|
||||
# This will only look in enabled hosts
|
||||
test2 = self.parser.find_dir(
|
||||
parser.case_i("documentroot"))
|
||||
self.assertEqual(len(test), 2)
|
||||
self.assertEqual(len(test2), 3)
|
||||
|
||||
def test_add_dir(self):
|
||||
aug_default = "/files" + self.parser.loc["default"]
|
||||
self.parser.add_dir(
|
||||
aug_default, "AddDirective", "test")
|
||||
|
||||
self.assertTrue(
|
||||
self.parser.find_dir("AddDirective", "test", aug_default))
|
||||
|
||||
self.parser.add_dir(aug_default, "AddList", ["1", "2", "3", "4"])
|
||||
matches = self.parser.find_dir("AddList", None, aug_default)
|
||||
for i, match in enumerate(matches):
|
||||
self.assertEqual(self.parser.aug.get(match), str(i + 1))
|
||||
|
||||
def test_add_dir_to_ifmodssl(self):
|
||||
"""test add_dir_to_ifmodssl.
|
||||
|
||||
Path must be valid before attempting to add to augeas
|
||||
|
||||
"""
|
||||
self.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(self.parser.loc["default"]),
|
||||
"FakeDirective", "123")
|
||||
|
||||
matches = self.parser.find_dir("FakeDirective", "123")
|
||||
|
||||
self.assertEqual(len(matches), 1)
|
||||
self.assertTrue("IfModule" in matches[0])
|
||||
|
||||
def test_get_aug_path(self):
|
||||
self.assertEqual(
|
||||
"/files/etc/apache", parser.get_aug_path("/etc/apache"))
|
||||
|
||||
def test_set_locations(self):
|
||||
with mock.patch("letsencrypt.client.apache.parser."
|
||||
"os.path") as mock_path:
|
||||
|
||||
mock_path.isfile.return_value = False
|
||||
|
||||
# pylint: disable=protected-access
|
||||
self.assertRaises(errors.LetsEncryptConfiguratorError,
|
||||
self.parser._set_locations, self.ssl_options)
|
||||
|
||||
mock_path.isfile.side_effect = [True, False, False]
|
||||
|
||||
# pylint: disable=protected-access
|
||||
results = self.parser._set_locations(self.ssl_options)
|
||||
|
||||
self.assertEqual(results["default"], results["listen"])
|
||||
self.assertEqual(results["default"], results["name"])
|
||||
94
letsencrypt/client/tests/config_util.py
Normal file
94
letsencrypt/client/tests/config_util.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import os
|
||||
import pkg_resources
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client.apache import configurator
|
||||
from letsencrypt.client.apache import obj
|
||||
from letsencrypt.client.apache import parser
|
||||
|
||||
|
||||
def dir_setup(test_dir="debian_apache_2_4/two_vhost_80"):
|
||||
"""Setup the directories necessary for the configurator."""
|
||||
temp_dir = tempfile.mkdtemp("temp")
|
||||
config_dir = tempfile.mkdtemp("config")
|
||||
work_dir = tempfile.mkdtemp("work")
|
||||
|
||||
test_configs = pkg_resources.resource_filename(
|
||||
__name__, "testdata/%s" % test_dir)
|
||||
|
||||
shutil.copytree(
|
||||
test_configs, os.path.join(temp_dir, test_dir), symlinks=True)
|
||||
|
||||
return temp_dir, config_dir, work_dir
|
||||
|
||||
|
||||
def setup_apache_ssl_options(config_dir):
|
||||
"""Move the ssl_options into position and return the path."""
|
||||
option_path = os.path.join(config_dir, "options-ssl.conf")
|
||||
temp_options = pkg_resources.resource_filename(
|
||||
"letsencrypt.client", os.path.basename(CONFIG.OPTIONS_SSL_CONF))
|
||||
shutil.copyfile(
|
||||
temp_options, 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."""
|
||||
|
||||
backups = os.path.join(work_dir, "backups")
|
||||
|
||||
with mock.patch("letsencrypt.client.apache.configurator."
|
||||
"subprocess.Popen") as mock_popen:
|
||||
# This just states that the ssl module is already loaded
|
||||
mock_popen().communicate.return_value = ("ssl_module", "")
|
||||
config = configurator.ApacheConfigurator(
|
||||
config_path,
|
||||
{
|
||||
"backup": backups,
|
||||
"temp": os.path.join(work_dir, "temp_checkpoint"),
|
||||
"progress": os.path.join(backups, "IN_PROGRESS"),
|
||||
"config": config_dir,
|
||||
"work": work_dir,
|
||||
},
|
||||
ssl_options,
|
||||
version)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def get_vh_truth(temp_dir, config_name):
|
||||
"""Return the ground truth for the specified directory."""
|
||||
if config_name == "debian_apache_2_4/two_vhost_80":
|
||||
prefix = os.path.join(
|
||||
temp_dir, config_name, "apache2/sites-available")
|
||||
aug_pre = "/files" + prefix
|
||||
vh_truth = [
|
||||
obj.VirtualHost(
|
||||
os.path.join(prefix, "encryption-example.conf"),
|
||||
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
|
||||
set([obj.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),
|
||||
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(["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(["letsencrypt.demo"])),
|
||||
]
|
||||
return vh_truth
|
||||
|
||||
return None
|
||||
|
|
@ -5,9 +5,6 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import zope.interface
|
||||
|
||||
from letsencrypt.client import apache_configurator
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import client
|
||||
from letsencrypt.client import display
|
||||
|
|
@ -15,6 +12,8 @@ from letsencrypt.client import interfaces
|
|||
from letsencrypt.client import errors
|
||||
from letsencrypt.client import log
|
||||
|
||||
from letsencrypt.client.apache import configurator
|
||||
|
||||
|
||||
def main():
|
||||
"""Command line argument parsing and main script execution."""
|
||||
|
|
@ -82,11 +81,11 @@ def main():
|
|||
display.set_display(display.FileDisplay(sys.stdout))
|
||||
|
||||
if args.rollback > 0:
|
||||
rollback(apache_configurator.ApacheConfigurator(), args.rollback)
|
||||
rollback(configurator.ApacheConfigurator(), args.rollback)
|
||||
sys.exit()
|
||||
|
||||
if args.view_checkpoints:
|
||||
view_checkpoints(apache_configurator.ApacheConfigurator())
|
||||
view_checkpoints(configurator.ApacheConfigurator())
|
||||
sys.exit()
|
||||
|
||||
server = args.server is None and CONFIG.ACME_SERVER or args.server
|
||||
|
|
@ -122,7 +121,7 @@ def main():
|
|||
# Validate the key and csr
|
||||
client.validate_key_csr(privkey, csr, domains)
|
||||
|
||||
cert_file, chain_file = acme.obtain_certificate(privkey, csr)
|
||||
cert_file, chain_file = acme.obtain_certificate(csr)
|
||||
vhost = acme.deploy_certificate(privkey, cert_file, chain_file)
|
||||
acme.optimize_config(vhost, args.redirect)
|
||||
|
||||
|
|
@ -176,20 +175,19 @@ def get_all_names(installer):
|
|||
# This should be controlled by commandline parameters
|
||||
def determine_authenticator():
|
||||
"""Returns a valid authenticator."""
|
||||
|
||||
try:
|
||||
return apache_configurator.ApacheConfigurator()
|
||||
return configurator.ApacheConfigurator()
|
||||
except errors.LetsEncryptConfiguratorError:
|
||||
log.info("Unable to find a way to authenticate.")
|
||||
logging.info("Unable to find a way to authenticate.")
|
||||
|
||||
|
||||
def determine_installer():
|
||||
"""Returns a valid installer if one exists."""
|
||||
|
||||
try:
|
||||
return apache_configurator.ApacheConfigurator()
|
||||
print "shouldn't ha;ppppen!!!!!!!!!!!!!!!!!!!"
|
||||
return configurator.ApacheConfigurator()
|
||||
except errors.LetsEncryptConfiguratorError:
|
||||
log.info("Unable to find a way to install the certificate.")
|
||||
logging.info("Unable to find a way to install the certificate.")
|
||||
|
||||
|
||||
def read_file(filename):
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -37,6 +37,7 @@ setup(
|
|||
'letsencrypt',
|
||||
'letsencrypt.client',
|
||||
'letsencrypt.client.apache',
|
||||
'letsencrypt.client.tests',
|
||||
'letsencrypt.scripts',
|
||||
],
|
||||
install_requires=install_requires,
|
||||
|
|
|
|||
2
tox.ini
2
tox.ini
|
|
@ -14,7 +14,7 @@ commands =
|
|||
[testenv:cover]
|
||||
commands =
|
||||
python setup.py dev
|
||||
python setup.py nosetests --with-coverage --cover-min-percentage=44
|
||||
python setup.py nosetests --with-coverage --cover-min-percentage=47
|
||||
|
||||
[testenv:lint]
|
||||
commands =
|
||||
|
|
|
|||
Loading…
Reference in a new issue