mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
Merge pull request #117 from letsencrypt/configurator_tests
Configurator tests
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
recursive-include letsencrypt *.json
|
||||
recursive-include letsencrypt *.sh
|
||||
recursive-include letsencrypt *.conf
|
||||
recursive include letsencrypt/client/tests/testdata *
|
||||
|
||||
@@ -10,6 +10,7 @@ If you create your own server... change this line
|
||||
Note: the server certificate must be trusted in order to avoid
|
||||
further modifications to the client."""
|
||||
|
||||
# Directories
|
||||
SERVER_ROOT = "/etc/apache2/"
|
||||
"""Apache server root directory"""
|
||||
|
||||
@@ -39,6 +40,7 @@ KEY_DIR = os.path.join(SERVER_ROOT, "ssl/")
|
||||
CERT_DIR = os.path.join(SERVER_ROOT, "certs/")
|
||||
"""Certificate storage"""
|
||||
|
||||
# Files and extensions
|
||||
OPTIONS_SSL_CONF = os.path.join(CONFIG_DIR, "options-ssl.conf")
|
||||
"""Contains standard Apache SSL directives"""
|
||||
|
||||
@@ -48,18 +50,6 @@ LE_VHOST_EXT = "-le-ssl.conf"
|
||||
APACHE_CHALLENGE_CONF = os.path.join(CONFIG_DIR, "le_dvsni_cert_challenge.conf")
|
||||
"""Temporary file for challenge virtual hosts"""
|
||||
|
||||
S_SIZE = 32
|
||||
"""Byte size of S"""
|
||||
|
||||
NONCE_SIZE = 16
|
||||
"""byte size of Nonce"""
|
||||
|
||||
RSA_KEY_SIZE = 2048
|
||||
"""Key size"""
|
||||
|
||||
DIFFICULTY = 23
|
||||
"""bits of hashcash to generate"""
|
||||
|
||||
CERT_PATH = CERT_DIR + "cert-letsencrypt.pem"
|
||||
"""Let's Encrypt cert file."""
|
||||
|
||||
@@ -69,6 +59,7 @@ CHAIN_PATH = CERT_DIR + "chain-letsencrypt.pem"
|
||||
INVALID_EXT = ".acme.invalid"
|
||||
"""Invalid Extension"""
|
||||
|
||||
# Challenge Information
|
||||
CHALLENGE_PREFERENCES = ["dvsni", "recoveryToken"]
|
||||
"""Challenge Preferences Dict for currently supported challenges"""
|
||||
|
||||
@@ -78,6 +69,25 @@ EXCLUSIVE_CHALLENGES = [frozenset(["dvsni", "simpleHttps"])]
|
||||
CONFIG_CHALLENGES = frozenset(["dvsni", "simpleHttps"])
|
||||
"""These are challenges that must be solved by a Configurator object"""
|
||||
|
||||
# Challenge Constants
|
||||
S_SIZE = 32
|
||||
"""Byte size of S"""
|
||||
|
||||
NONCE_SIZE = 16
|
||||
"""byte size of Nonce"""
|
||||
|
||||
# Key Sizes
|
||||
RSA_KEY_SIZE = 2048
|
||||
"""Key size"""
|
||||
|
||||
# Config Optimizations
|
||||
REWRITE_HTTPS_ARGS = [
|
||||
"^.*$", "https://%{SERVER_NAME}%{REQUEST_URI}", "[L,R=permanent]"]
|
||||
"""Rewrite rule arguments used for redirections to https vhost"""
|
||||
|
||||
# Apache Interaction
|
||||
APACHE_CTL = "/usr/sbin/apache2ctl"
|
||||
"""Command used for configtest and version number."""
|
||||
|
||||
APACHE2 = "/etc/init.d/apache2"
|
||||
"""Command used for reload and restart."""
|
||||
|
||||
@@ -7,7 +7,7 @@ import jsonschema
|
||||
from letsencrypt.client import crypto_util
|
||||
from letsencrypt.client import le_util
|
||||
|
||||
|
||||
# pylint: disable=no-member
|
||||
SCHEMATA = dict([
|
||||
(schema, json.load(open(pkg_resources.resource_filename(
|
||||
__name__, "schemata/%s.json" % schema)))) for schema in [
|
||||
|
||||
@@ -7,7 +7,6 @@ import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
from Crypto import Random
|
||||
|
||||
@@ -47,24 +46,20 @@ from letsencrypt.client import logger
|
||||
class VH(object):
|
||||
"""Represents an Apache Virtualhost.
|
||||
|
||||
:ivar str file: filename path of VH
|
||||
|
||||
:ivar str filep: file path of VH
|
||||
:ivar str path: Augeas path to virtual host
|
||||
|
||||
:ivar list addrs: Virtual Host addresses (:class:`list` of :class:`str`)
|
||||
|
||||
:ivar list names: Server names/aliases of vhost
|
||||
(:class:`list` of :class:`str`)
|
||||
|
||||
:ivar bool ssl: SSLEngine on in vhost
|
||||
|
||||
:ivar bool enabled: Virtual host is enabled
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filename, path, addrs, ssl, enabled):
|
||||
def __init__(self, filep, path, addrs, ssl, enabled):
|
||||
"""Initialize a VH."""
|
||||
self.file = filename
|
||||
self.filep = filep
|
||||
self.path = path
|
||||
self.addrs = addrs
|
||||
self.names = []
|
||||
@@ -85,9 +80,18 @@ class VH(object):
|
||||
"addrs: %s\n"
|
||||
"names: %s\n"
|
||||
"ssl: %s\n"
|
||||
"enabled: %s" % (self.file, self.path, self.addrs,
|
||||
"enabled: %s" % (self.filep, self.path, self.addrs,
|
||||
self.names, self.ssl, self.enabled))
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
return (self.filep == other.filep and self.path == other.path and
|
||||
set(self.addrs) == set(other.addrs) and
|
||||
set(self.names) == set(other.names) and
|
||||
self.ssl == other.ssl and self.enabled == other.enabled)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"""Apache configurator.
|
||||
@@ -98,37 +102,49 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
This class was originally developed for Apache 2.2 and has not seen a
|
||||
an overhaul to include proper setup of new Apache configurations.
|
||||
The biggest changes have been the IncludeOptional directive, the
|
||||
deprecation of the NameVirtualHost directive, and the name change of
|
||||
mod_ssl.c to ssl_module. Although these changes
|
||||
have not been implemented yet, they will be shortly.
|
||||
I have implemented most of the changes... the missing ones are
|
||||
mod_ssl.c vs ssl_mod, and I need to account for configuration variables.
|
||||
That being said, this class can still adequately configure most typical
|
||||
Apache 2.4 servers as the deprecated NameVirtualHost has no effect
|
||||
and the typical directories are parsed by the Augeas configuration
|
||||
parser automatically.
|
||||
|
||||
.. todo:: Add support for config file variables Define rootDir /var/www/
|
||||
|
||||
The API of this class will change in the coming weeks as the exact
|
||||
needs of client's are clarified with the new and developing protocol.
|
||||
|
||||
This class will eventually derive from a generic Configurator class
|
||||
so that other Configurators (like Nginx) can be developed and interoperate
|
||||
with the client.
|
||||
|
||||
:ivar str server_root: Path to Apache root directory
|
||||
|
||||
:ivar dict location: Path to various files associated
|
||||
with the configuration
|
||||
:ivar float version: version of Apache
|
||||
|
||||
:ivar str user_config_file: Path to the user's configuration file
|
||||
|
||||
:ivar list vhosts: All vhosts found in the configuration
|
||||
(:class:`list` of :class:`VH`)
|
||||
|
||||
:ivar dict assoc: Mapping between domains and vhosts
|
||||
|
||||
"""
|
||||
def __init__(self, server_root=CONFIG.SERVER_ROOT):
|
||||
"""Initialize an Apache Configurator."""
|
||||
super(ApacheConfigurator, self).__init__()
|
||||
def __init__(self, server_root=CONFIG.SERVER_ROOT, direc=None,
|
||||
ssl_options=CONFIG.OPTIONS_SSL_CONF, version=None):
|
||||
"""Initialize an Apache Configurator.
|
||||
|
||||
:param str server_root: the apache server root directory
|
||||
:param dict direc: locations of various config directories
|
||||
(used mostly for unittesting)
|
||||
:param str ssl_options: path of options-ssl.conf
|
||||
(used mostly for unittesting)
|
||||
:param tup version: version of Apache as a tuple (2, 4, 7)
|
||||
(used mostly for unittesting)
|
||||
|
||||
"""
|
||||
if direc is None:
|
||||
direc = {"backup": CONFIG.BACKUP_DIR,
|
||||
"temp": CONFIG.TEMP_CHECKPOINT_DIR,
|
||||
"progress": CONFIG.IN_PROGRESS_DIR,
|
||||
"config": CONFIG.CONFIG_DIR,
|
||||
"work": CONFIG.WORK_DIR}
|
||||
|
||||
super(ApacheConfigurator, self).__init__(direc)
|
||||
|
||||
self.server_root = server_root
|
||||
|
||||
@@ -138,28 +154,37 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
# vhosts
|
||||
self.recovery_routine()
|
||||
|
||||
# Verify that all directories and files exist with proper permissions
|
||||
if os.geteuid() == 0:
|
||||
self.verify_setup()
|
||||
|
||||
# Find configuration root and make sure augeas can parse it.
|
||||
self.location = self._set_locations(ssl_options)
|
||||
self._parse_file(self.location["root"])
|
||||
|
||||
# Must also attempt to parse sites-available or equivalent
|
||||
# Sites-available is not included naturally in configuration
|
||||
self._parse_file(os.path.join(self.server_root, "sites-available/*"))
|
||||
|
||||
# Set Version
|
||||
self.version = self.get_version() if version is None else version
|
||||
|
||||
# Check for errors in parsing files with Augeas
|
||||
self.check_parsing_errors("httpd.aug")
|
||||
# This problem has been fixed in Augeas 1.0
|
||||
self.standardize_excl()
|
||||
|
||||
# Determine user's main config file
|
||||
self.user_config_file = self._set_user_config_file()
|
||||
|
||||
# Get all of the available vhosts
|
||||
self.vhosts = self.get_virtual_hosts()
|
||||
# Add name_server association dict
|
||||
self.assoc = dict()
|
||||
# Verify that all directories and files exist with proper permissions
|
||||
verify_setup()
|
||||
|
||||
# Enable mod_ssl if it isn't already enabled
|
||||
# This is Let's Encrypt... we enable mod_ssl on initialization :)
|
||||
# TODO: attempt to make the check faster... this enable should
|
||||
# be asynchronous as it shouldn't be that time sensitive
|
||||
# on initialization
|
||||
if not check_ssl_loaded():
|
||||
logger.info("Loading mod_ssl into Apache Server")
|
||||
enable_mod("ssl")
|
||||
self._prepare_server_https()
|
||||
|
||||
# Note: initialization doesn't check to see if the config is correct
|
||||
# by Apache's standards. This should be done by the client (client.py)
|
||||
@@ -214,7 +239,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
# Presumably break here so that the virtualhost is not modified
|
||||
return False
|
||||
|
||||
logger.info("Deploying Certificate to VirtualHost %s" % vhost.file)
|
||||
logger.info("Deploying Certificate to VirtualHost %s" % vhost.filep)
|
||||
|
||||
self.aug.set(path["cert_file"][0], cert)
|
||||
self.aug.set(path["cert_key"][0], key)
|
||||
@@ -225,7 +250,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
self.aug.set(path["cert_chain"][0], cert_chain)
|
||||
|
||||
self.save_notes += ("Changed vhost at %s with addresses of %s\n" %
|
||||
(vhost.file, vhost.addrs))
|
||||
(vhost.filep, vhost.addrs))
|
||||
self.save_notes += "\tSSLCertificateFile %s\n" % cert
|
||||
self.save_notes += "\tSSLCertificateKeyFile %s\n" % key
|
||||
if cert_chain:
|
||||
@@ -322,6 +347,40 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
return all_names
|
||||
|
||||
def _set_locations(self, ssl_options):
|
||||
"""Set default location for directives.
|
||||
|
||||
Locations are given as file_paths
|
||||
.. todo:: Make sure that files are included
|
||||
|
||||
"""
|
||||
|
||||
root = self._find_config_root()
|
||||
default = self._set_user_config_file()
|
||||
|
||||
temp = os.path.join(self.server_root, "ports.conf")
|
||||
if os.path.isfile(temp):
|
||||
listen = temp
|
||||
name = temp
|
||||
else:
|
||||
listen = default
|
||||
name = default
|
||||
|
||||
return {"root": root, "default": default, "listen": listen,
|
||||
"name": name, "ssl_options": ssl_options}
|
||||
|
||||
def _find_config_root(self):
|
||||
"""Find the Apache Configuration Root file."""
|
||||
|
||||
location = ["apache2.conf", "httpd.conf"]
|
||||
|
||||
for name in location:
|
||||
if os.path.isfile(os.path.join(self.server_root, name)):
|
||||
return os.path.join(self.server_root, name)
|
||||
|
||||
raise errors.LetsEncryptConfiguratorError(
|
||||
"Could not find configuration root")
|
||||
|
||||
def _set_user_config_file(self, filename=''):
|
||||
"""Set the appropriate user configuration file
|
||||
|
||||
@@ -357,6 +416,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
case_i('ServerName'),
|
||||
host.path,
|
||||
case_i('ServerAlias'))))
|
||||
|
||||
for name in name_match:
|
||||
args = self.aug.match(name + "/*")
|
||||
for arg in args:
|
||||
@@ -377,8 +437,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
addrs.append(self.aug.get(arg))
|
||||
is_ssl = False
|
||||
|
||||
if len(self.find_directive(
|
||||
case_i("SSLEngine"), case_i("on"), path)) > 0:
|
||||
if self.find_directive(
|
||||
case_i("SSLEngine"), case_i("on"), path):
|
||||
is_ssl = True
|
||||
|
||||
filename = get_file_path(path)
|
||||
@@ -400,15 +460,19 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
("/files%ssites-available//*[label()=~regexp('%s')]" %
|
||||
(self.server_root, case_i('VirtualHost'))))
|
||||
vhs = []
|
||||
|
||||
for path in paths:
|
||||
vhs.append(self._create_vhost(path))
|
||||
|
||||
return vhs
|
||||
|
||||
# pylint: disable=anomalous-backslash-in-string
|
||||
def is_name_vhost(self, target_addr):
|
||||
"""Returns if vhost is a name based vhost
|
||||
|
||||
Checks if addr has a NameVirtualHost directive in the Apache config
|
||||
NameVirtualHost was deprecated in Apache 2.4 as all VirtualHosts are
|
||||
now NameVirtualHosts. If version is earlier than 2.4, check if addr
|
||||
has a NameVirtualHost directive in the Apache config
|
||||
|
||||
:param str addr: vhost address ie. \*:443
|
||||
|
||||
@@ -416,49 +480,28 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
# search for NameVirtualHost directive for ip_addr
|
||||
# check httpd.conf, ports.conf,
|
||||
# note ip_addr can be FQDN although Apache does not recommend it
|
||||
paths = self.find_directive(case_i("NameVirtualHost"), None)
|
||||
name_vh = []
|
||||
for path in paths:
|
||||
name_vh.append(self.aug.get(path))
|
||||
|
||||
# Mixed and matched wildcard NameVirtualHost with VirtualHost
|
||||
# behavior is undefined. Make sure that an exact match exists
|
||||
|
||||
# Check for exact match
|
||||
for addr in name_vh:
|
||||
if addr == target_addr:
|
||||
return True
|
||||
|
||||
return False
|
||||
# search for NameVirtualHost directive for ip_addr
|
||||
# note ip_addr can be FQDN although Apache does not recommend it
|
||||
return (self.version >= (2, 4) or
|
||||
self.find_directive(
|
||||
case_i("NameVirtualHost"), case_i(target_addr)))
|
||||
|
||||
def add_name_vhost(self, addr):
|
||||
"""Adds NameVirtualHost directive for given address.
|
||||
|
||||
Directive is added to ports.conf unless the file doesn't exist
|
||||
It is added to httpd.conf as a backup
|
||||
|
||||
:param str addr: Address that will be added as NameVirtualHost directive
|
||||
|
||||
"""
|
||||
aug_file_path = "/files%sports.conf" % self.server_root
|
||||
self.add_dir_to_ifmodssl(aug_file_path, "NameVirtualHost", addr)
|
||||
path = self._add_dir_to_ifmodssl(
|
||||
get_aug_path(self.location["name"]), "NameVirtualHost", addr)
|
||||
|
||||
# TODO: Check to see if len(find_dir) can just be if find_dir()
|
||||
if len(self.find_directive(
|
||||
case_i("NameVirtualHost"), case_i(addr))) == 0:
|
||||
logger.warn("ports.conf is not included in your Apache config...")
|
||||
logger.warn("Adding NameVirtualHost directive to httpd.conf")
|
||||
self.save_notes += "Setting %s to be NameBasedVirtualHost\n" % addr
|
||||
self.save_notes += "\tDirective added to %s\n" % path
|
||||
|
||||
self.add_dir_to_ifmodssl("/files%shttpd.conf" % self.server_root,
|
||||
"NameVirtualHost",
|
||||
addr)
|
||||
|
||||
self.save_notes += 'Setting %s to be NameBasedVirtualHost\n' % addr
|
||||
|
||||
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
||||
def _add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
||||
"""Adds directive and value to IfMod ssl block.
|
||||
|
||||
Adds given directive and value along configuration path within
|
||||
@@ -472,39 +515,45 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"""
|
||||
# TODO: Add error checking code... does the path given even exist?
|
||||
# Does it throw exceptions?
|
||||
if_mod_path = self.get_ifmod(aug_conf_path, "mod_ssl.c")
|
||||
if_mod_path = self._get_ifmod(aug_conf_path, "mod_ssl.c")
|
||||
# IfModule can have only one valid argument, so append after
|
||||
self.aug.insert(if_mod_path + "arg", "directive", False)
|
||||
nvh_path = if_mod_path + "directive[1]"
|
||||
self.aug.set(nvh_path, directive)
|
||||
self.aug.set(nvh_path + "/arg", val)
|
||||
|
||||
def _prepare_server_https(self):
|
||||
"""Prepare the server for HTTPS.
|
||||
|
||||
Make sure that the ssl_module is loaded and that the server
|
||||
is appropriately listening on port 443.
|
||||
|
||||
"""
|
||||
if not check_ssl_loaded():
|
||||
logger.info("Loading mod_ssl into Apache Server")
|
||||
enable_mod("ssl")
|
||||
|
||||
# Check for Listen 443
|
||||
# Note: This could be made to also look for ip:443 combo
|
||||
# TODO: Need to search only open directives and IfMod mod_ssl.c
|
||||
if len(self.find_directive(case_i("Listen"), "443")) == 0:
|
||||
logger.debug("No Listen 443 directive found")
|
||||
logger.debug("Setting the Apache Server to Listen on port 443")
|
||||
path = self._add_dir_to_ifmodssl(
|
||||
get_aug_path(self.location["listen"]), "Listen", "443")
|
||||
self.save_notes += "Added Listen 443 directive to %s\n" % path
|
||||
|
||||
def make_server_sni_ready(self, vhost, default_addr="*:443"):
|
||||
"""Checks to see if the server is ready for SNI challenges.
|
||||
|
||||
.. todo:: This should largely depend on the version of Apache
|
||||
|
||||
:param vhost: VHost to check SNI compatibility
|
||||
:type vhost: :class:`VH`
|
||||
|
||||
:param str default_addr: TODO - investigate function further
|
||||
|
||||
"""
|
||||
# Check if mod_ssl is loaded
|
||||
if not check_ssl_loaded():
|
||||
logger.error("Please load the SSL module with Apache")
|
||||
return False
|
||||
|
||||
# Check for Listen 443
|
||||
# TODO: This could be made to also look for ip:443 combo
|
||||
# TODO: Need to search only open directives and IfMod mod_ssl.c
|
||||
if len(self.find_directive(case_i("Listen"), "443")) == 0:
|
||||
logger.debug("No Listen 443 directive found")
|
||||
logger.debug("Setting the Apache Server to Listen on port 443")
|
||||
self.add_dir_to_ifmodssl("/files%sports.conf" % self.server_root,
|
||||
"Listen", "443")
|
||||
self.save_notes += "Added Listen 443 directive to ports.conf\n"
|
||||
|
||||
if self.version >= (2, 4):
|
||||
return
|
||||
# Check for NameVirtualHost
|
||||
# First see if any of the vhost addresses is a _default_ addr
|
||||
for addr in vhost.addrs:
|
||||
@@ -515,7 +564,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"%s to be name based vhosts" % default_addr))
|
||||
self.add_name_vhost(default_addr)
|
||||
|
||||
return True
|
||||
# No default addresses... so set each one individually
|
||||
for addr in vhost.addrs:
|
||||
if not self.is_name_vhost(addr):
|
||||
@@ -523,9 +571,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"to be a name based virtual host" % addr))
|
||||
self.add_name_vhost(addr)
|
||||
|
||||
return True
|
||||
|
||||
def get_ifmod(self, aug_conf_path, mod):
|
||||
def _get_ifmod(self, aug_conf_path, mod):
|
||||
"""Returns the path to <IfMod mod> and creates one if it doesn't exist.
|
||||
|
||||
:param str aug_conf_path: Augeas configuration path
|
||||
@@ -533,25 +579,25 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
"""
|
||||
if_mods = self.aug.match(("%s/IfModule/*[self::arg='%s']" %
|
||||
(aug_conf_path, mod)))
|
||||
(aug_conf_path, mod)))
|
||||
if len(if_mods) == 0:
|
||||
self.aug.set("%s/IfModule[last() + 1]" % aug_conf_path, "")
|
||||
self.aug.set("%s/IfModule[last()]/arg" % aug_conf_path, mod)
|
||||
if_mods = self.aug.match(("%s/IfModule/*[self::arg='%s']" %
|
||||
(aug_conf_path, mod)))
|
||||
(aug_conf_path, mod)))
|
||||
# Strip off "arg" at end of first ifmod path
|
||||
return if_mods[0][:len(if_mods[0]) - 3]
|
||||
|
||||
def add_dir(self, aug_conf_path, directive, arg):
|
||||
"""Appends directive to the end fo the file given by aug_conf_path.
|
||||
|
||||
Note: Not added to AugeasConfigurator because it may depend on the lens
|
||||
.. note:: Not added to AugeasConfigurator because it may depend
|
||||
on the lens
|
||||
|
||||
:param str aug_conf_path: Augeas configuration path to add directive
|
||||
:param str directive: Directive to add
|
||||
:param str arg: Value of the directive. ie. Listen 443, 443 is arg
|
||||
|
||||
|
||||
"""
|
||||
self.aug.set(aug_conf_path + "/directive[last() + 1]", directive)
|
||||
if type(arg) is not list:
|
||||
@@ -588,7 +634,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"""
|
||||
# Cannot place member variable in the definition of the function so...
|
||||
if not start:
|
||||
start = "/files%sapache2.conf" % self.server_root
|
||||
start = get_aug_path(self.location["root"])
|
||||
|
||||
# Debug code
|
||||
# print "find_dir:", directive, "arg:", arg, " | Looking in:", start
|
||||
@@ -611,19 +657,24 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"[self::arg=~regexp('%s')]" %
|
||||
(start, directive, arg)))
|
||||
|
||||
incl_regex = "(%s)|(%s)" % (case_i('Include'),
|
||||
case_i('IncludeOptional'))
|
||||
|
||||
includes = self.aug.match(("%s//* [self::directive=~regexp('%s')]/* "
|
||||
"[label()='arg']" %
|
||||
(start, case_i('Include'))))
|
||||
"[label()='arg']" % (start, incl_regex)))
|
||||
|
||||
# for inc in includes:
|
||||
# print inc, self.aug.get(inc)
|
||||
|
||||
for include in includes:
|
||||
# start[6:] to strip off /files
|
||||
matches.extend(self.find_directive(
|
||||
directive, arg, self.get_include_path(strip_dir(start[6:]),
|
||||
self.aug.get(include))))
|
||||
directive, arg, self._get_include_path(strip_dir(start[6:]),
|
||||
self.aug.get(include))))
|
||||
|
||||
return matches
|
||||
|
||||
def get_include_path(self, cur_dir, arg):
|
||||
def _get_include_path(self, cur_dir, arg):
|
||||
"""Converts an Apache Include directive into Augeas path.
|
||||
|
||||
Converts an Apache Include directive argument into an Augeas
|
||||
@@ -689,8 +740,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
# If the include is a directory, just return the directory as a file
|
||||
if arg.endswith("/"):
|
||||
return "/files" + arg[:len(arg)-1]
|
||||
return "/files"+arg
|
||||
return get_aug_path(arg[:len(arg)-1])
|
||||
return get_aug_path(arg)
|
||||
|
||||
def make_vhost_ssl(self, nonssl_vhost):
|
||||
"""Makes an ssl_vhost version of a nonssl_vhost.
|
||||
@@ -705,7 +756,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
:rtype: :class:`VH`
|
||||
|
||||
"""
|
||||
avail_fp = nonssl_vhost.file
|
||||
avail_fp = nonssl_vhost.filep
|
||||
# Copy file
|
||||
if avail_fp.endswith(".conf"):
|
||||
ssl_fp = avail_fp[:-(len(".conf"))] + CONFIG.LE_VHOST_EXT
|
||||
@@ -743,8 +794,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
addr_match % (avail_fp, case_i('VirtualHost')))
|
||||
|
||||
for i in range(len(avail_addr_p)):
|
||||
avail_old_arg = self.aug.get(avail_addr_p[i])
|
||||
ssl_old_arg = self.aug.get(ssl_addr_p[i])
|
||||
avail_old_arg = str(self.aug.get(avail_addr_p[i]))
|
||||
ssl_old_arg = str(self.aug.get(ssl_addr_p[i]))
|
||||
avail_tup = avail_old_arg.partition(":")
|
||||
ssl_tup = ssl_old_arg.partition(":")
|
||||
avail_new_addr = avail_tup[0] + ":80"
|
||||
@@ -765,7 +816,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"/etc/ssl/certs/ssl-cert-snakeoil.pem")
|
||||
self.add_dir(vh_p[0], "SSLCertificateKeyFile",
|
||||
"/etc/ssl/private/ssl-cert-snakeoil.key")
|
||||
self.add_dir(vh_p[0], "Include", CONFIG.OPTIONS_SSL_CONF)
|
||||
self.add_dir(vh_p[0], "Include", self.location["ssl_options"])
|
||||
|
||||
# Log actions and create save notes
|
||||
logger.info("Created an SSL vhost at %s" % ssl_fp)
|
||||
@@ -835,7 +886,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
self.add_dir(general_v.path,
|
||||
"RewriteRule", CONFIG.REWRITE_HTTPS_ARGS)
|
||||
self.save_notes += ('Redirecting host in %s to ssl vhost in %s\n' %
|
||||
(general_v.file, ssl_vhost.file))
|
||||
(general_v.filep, ssl_vhost.filep))
|
||||
self.save()
|
||||
return True, general_v
|
||||
|
||||
@@ -946,13 +997,13 @@ LogLevel warn \n\
|
||||
self.aug.load()
|
||||
# Make a new vhost data structure and add it to the lists
|
||||
new_fp = self.server_root + "sites-available/" + redirect_filename
|
||||
new_vhost = self._create_vhost("/files" + new_fp)
|
||||
new_vhost = self._create_vhost(get_aug_path(new_fp))
|
||||
self.vhosts.append(new_vhost)
|
||||
|
||||
# Finally create documentation for the change
|
||||
self.save_notes += ('Created a port 80 vhost, %s, for redirection to '
|
||||
'ssl vhost %s\n' %
|
||||
(new_vhost.file, ssl_vhost.file))
|
||||
(new_vhost.filep, ssl_vhost.filep))
|
||||
|
||||
return True, new_vhost
|
||||
|
||||
@@ -1071,7 +1122,7 @@ LogLevel warn \n\
|
||||
# Can be removed once find directive can return ordered results
|
||||
if len(cert_path) != 1 or len(key_path) != 1:
|
||||
logger.error(("Too many cert or key directives in vhost "
|
||||
"%s" % vhost.file))
|
||||
"%s" % vhost.filep))
|
||||
sys.exit(40)
|
||||
|
||||
cert = os.path.abspath(self.aug.get(cert_path[0]))
|
||||
@@ -1112,17 +1163,17 @@ LogLevel warn \n\
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
if self.is_site_enabled(vhost.file):
|
||||
if self.is_site_enabled(vhost.filep):
|
||||
return True
|
||||
|
||||
if "/sites-available/" in vhost.file:
|
||||
if "/sites-available/" in vhost.filep:
|
||||
enabled_path = ("%ssites-enabled/%s" %
|
||||
(self.server_root, os.path.basename(vhost.file)))
|
||||
(self.server_root, os.path.basename(vhost.filep)))
|
||||
self.register_file_creation(False, enabled_path)
|
||||
os.symlink(vhost.file, enabled_path)
|
||||
os.symlink(vhost.filep, enabled_path)
|
||||
vhost.enabled = True
|
||||
logger.info("Enabling available site: %s" % vhost.file)
|
||||
self.save_notes += 'Enabled site %s\n' % vhost.file
|
||||
logger.info("Enabling available site: %s" % vhost.filep)
|
||||
self.save_notes += 'Enabled site %s\n' % vhost.filep
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -1170,13 +1221,6 @@ LogLevel warn \n\
|
||||
self._add_httpd_transform(file_path)
|
||||
self.aug.load()
|
||||
|
||||
def save_apache_config(self):
|
||||
"""Backup complete Apache config. Not currently used."""
|
||||
# Not currently used
|
||||
# Should be safe because it is a protected directory
|
||||
shutil.copytree(self.server_root,
|
||||
"%sapache2-%s" % (CONFIG.BACKUP_DIR, str(time.time())))
|
||||
|
||||
def standardize_excl(self):
|
||||
"""Standardize the excl arguments for the Httpd lens in Augeas.
|
||||
|
||||
@@ -1216,7 +1260,7 @@ LogLevel warn \n\
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
return apache_restart(quiet)
|
||||
return apache_restart()
|
||||
|
||||
def _add_httpd_transform(self, incl):
|
||||
"""Add a transform to Augeas.
|
||||
@@ -1257,6 +1301,50 @@ LogLevel warn \n\
|
||||
|
||||
return True
|
||||
|
||||
def get_version(self): # pylint: disable=no-self-use
|
||||
"""Return version of Apache Server.
|
||||
|
||||
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
|
||||
|
||||
:returns: version
|
||||
:rtype: tuple
|
||||
|
||||
:raises errors.LetsEncryptConfiguratorError:
|
||||
Unable to find Apache version
|
||||
|
||||
"""
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
[CONFIG.APACHE_CTL, '-v'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
text = proc.communicate()[0]
|
||||
except (OSError, ValueError):
|
||||
raise errors.LetsEncryptConfiguratorError(
|
||||
"Unable to run %s -v" % CONFIG.APACHE_CTL)
|
||||
|
||||
regex = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
|
||||
matches = regex.findall(text)
|
||||
|
||||
if len(matches) != 1:
|
||||
raise errors.LetsEncryptConfiguratorError(
|
||||
"Unable to find Apache version")
|
||||
|
||||
return tuple([int(i) for i in matches[0].split('.')])
|
||||
|
||||
def verify_setup(self):
|
||||
"""Verify the setup to ensure safe operating environment.
|
||||
|
||||
Make sure that files/directories are setup with appropriate permissions
|
||||
Aim for defensive coding... make sure all input files
|
||||
have permissions of root
|
||||
|
||||
"""
|
||||
uid = os.geteuid()
|
||||
le_util.make_or_verify_dir(self.direc["config"], 0o755, uid)
|
||||
le_util.make_or_verify_dir(self.direc["work"], 0o755, uid)
|
||||
le_util.make_or_verify_dir(self.direc["backup"], 0o755, uid)
|
||||
|
||||
###########################################################################
|
||||
# Challenges Section
|
||||
###########################################################################
|
||||
@@ -1312,8 +1400,7 @@ LogLevel warn \n\
|
||||
return None
|
||||
|
||||
# TODO - @jdkasten review this code to make sure it makes sense
|
||||
if not self.make_server_sni_ready(vhost, default_addr):
|
||||
return None
|
||||
self.make_server_sni_ready(vhost, default_addr)
|
||||
|
||||
for addr in vhost.addrs:
|
||||
if "_default_" in addr:
|
||||
@@ -1370,6 +1457,7 @@ LogLevel warn \n\
|
||||
# SHOWING A NICE ERROR MESSAGE ABOUT THE PROBLEM
|
||||
|
||||
# Check to make sure options-ssl.conf is installed
|
||||
# pylint: disable=no-member
|
||||
if not os.path.isfile(CONFIG.OPTIONS_SSL_CONF):
|
||||
dist_conf = pkg_resources.resource_filename(
|
||||
__name__, os.path.basename(CONFIG.OPTIONS_SSL_CONF))
|
||||
@@ -1378,11 +1466,11 @@ LogLevel warn \n\
|
||||
# TODO: Use ip address of existing vhost instead of relying on FQDN
|
||||
config_text = "<IfModule mod_ssl.c> \n"
|
||||
for idx, lis in enumerate(ll_addrs):
|
||||
config_text += get_config_text(
|
||||
config_text += self.get_config_text(
|
||||
list_sni_tuple[idx][2], lis, dvsni_key.file)
|
||||
config_text += "</IfModule> \n"
|
||||
|
||||
self.dvsni_conf_include_check(self.user_config_file)
|
||||
self.dvsni_conf_include_check(self.location["default"])
|
||||
self.register_file_creation(True, CONFIG.APACHE_CHALLENGE_CONF)
|
||||
|
||||
with open(CONFIG.APACHE_CHALLENGE_CONF, 'w') as new_conf:
|
||||
@@ -1400,13 +1488,13 @@ LogLevel warn \n\
|
||||
if len(self.find_directive(
|
||||
case_i("Include"), CONFIG.APACHE_CHALLENGE_CONF)) == 0:
|
||||
# print "Including challenge virtual host(s)"
|
||||
self.add_dir("/files" + main_config,
|
||||
self.add_dir(get_aug_path(main_config),
|
||||
"Include", CONFIG.APACHE_CHALLENGE_CONF)
|
||||
|
||||
def dvsni_create_chall_cert(self, name, ext, nonce, dvsni_key):
|
||||
"""Creates DVSNI challenge certifiate.
|
||||
|
||||
Certificate created at dvsni_get_cert_file(nonce)
|
||||
Certificate created at self.dvsni_get_cert_file(nonce)
|
||||
|
||||
:param str nonce: hex form of nonce
|
||||
|
||||
@@ -1414,14 +1502,50 @@ LogLevel warn \n\
|
||||
:type dvsni_key: `client.Client.Key`
|
||||
|
||||
"""
|
||||
self.register_file_creation(True, dvsni_get_cert_file(nonce))
|
||||
self.register_file_creation(True, self.dvsni_get_cert_file(nonce))
|
||||
|
||||
cert_pem = crypto_util.make_ss_cert(
|
||||
dvsni_key.pem, [nonce + CONFIG.INVALID_EXT, name, ext])
|
||||
|
||||
with open(dvsni_get_cert_file(nonce), 'w') as chall_cert_file:
|
||||
with open(self.dvsni_get_cert_file(nonce), 'w') as chall_cert_file:
|
||||
chall_cert_file.write(cert_pem)
|
||||
|
||||
def get_config_text(self, nonce, ip_addrs, dvsni_key_file):
|
||||
"""Chocolate virtual server configuration text
|
||||
|
||||
:param str nonce: hex form of nonce
|
||||
:param str ip_addrs: addresses of challenged domain
|
||||
:param str dvsni_key_file: Path to key file
|
||||
|
||||
:returns: virtual host configuration text
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
return ("<VirtualHost " + " ".join(ip_addrs) + "> \n"
|
||||
"ServerName " + nonce + CONFIG.INVALID_EXT + " \n"
|
||||
"UseCanonicalName on \n"
|
||||
"SSLStrictSNIVHostCheck on \n"
|
||||
"\n"
|
||||
"LimitRequestBody 1048576 \n"
|
||||
"\n"
|
||||
"Include " + self.location["ssl_options"] + " \n"
|
||||
"SSLCertificateFile " + self.dvsni_get_cert_file(nonce) + " \n"
|
||||
"SSLCertificateKeyFile " + dvsni_key_file + " \n"
|
||||
"\n"
|
||||
"DocumentRoot " + self.direc["config"] + "challenge_page/ \n"
|
||||
"</VirtualHost> \n\n")
|
||||
|
||||
def dvsni_get_cert_file(self, nonce):
|
||||
"""Returns standardized name for challenge certificate.
|
||||
|
||||
:param str nonce: hex form of nonce
|
||||
|
||||
:returns: certificate file name
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
return self.direc["work"] + nonce + ".crt"
|
||||
|
||||
|
||||
def enable_mod(mod_name):
|
||||
"""Enables module in Apache.
|
||||
@@ -1437,7 +1561,7 @@ def enable_mod(mod_name):
|
||||
stdout=open("/dev/null", 'w'),
|
||||
stderr=open("/dev/null", 'w'))
|
||||
# Hopefully this waits for output
|
||||
subprocess.check_call(["sudo", "/etc/init.d/apache2", "restart"],
|
||||
subprocess.check_call(["sudo", CONFIG.APACHE2, "restart"],
|
||||
stdout=open("/dev/null", 'w'),
|
||||
stderr=open("/dev/null", 'w'))
|
||||
except (OSError, subprocess.CalledProcessError) as err:
|
||||
@@ -1460,12 +1584,13 @@ def check_ssl_loaded():
|
||||
try:
|
||||
# p=subprocess.check_output(['sudo', '/usr/sbin/apache2ctl', '-M'],
|
||||
# stderr=open("/dev/null", 'w'))
|
||||
proc = subprocess.Popen(['sudo', '/usr/sbin/apache2ctl', '-M'],
|
||||
proc = subprocess.Popen([CONFIG.APACHE_CTL, '-M'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=open(
|
||||
"/dev/null", 'w')).communicate()[0]
|
||||
except (OSError, ValueError):
|
||||
logger.error("Error accessing apache2ctl for loaded modules!")
|
||||
logger.error(
|
||||
"Error accessing %s for loaded modules!" % CONFIG.APACHE_CTL)
|
||||
logger.error("This may be caused by an Apache Configuration Error")
|
||||
return False
|
||||
|
||||
@@ -1474,7 +1599,7 @@ def check_ssl_loaded():
|
||||
return False
|
||||
|
||||
|
||||
def apache_restart(quiet=False):
|
||||
def apache_restart():
|
||||
"""Restarts the Apache Server.
|
||||
|
||||
.. todo:: Try to use reload instead. (This caused timing problems before)
|
||||
@@ -1482,7 +1607,7 @@ def apache_restart(quiet=False):
|
||||
|
||||
"""
|
||||
try:
|
||||
proc = subprocess.Popen(['/etc/init.d/apache2', 'restart'],
|
||||
proc = subprocess.Popen([CONFIG.APACHE2, 'restart'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
text = proc.communicate()
|
||||
@@ -1502,19 +1627,6 @@ def apache_restart(quiet=False):
|
||||
return True
|
||||
|
||||
|
||||
def verify_setup():
|
||||
"""Verify the setup to ensure safe operating environment.
|
||||
|
||||
Make sure that files/directories are setup with appropriate permissions
|
||||
Aim for defensive coding... make sure all input files
|
||||
have permissions of root
|
||||
|
||||
"""
|
||||
le_util.make_or_verify_dir(CONFIG.CONFIG_DIR, 0o755)
|
||||
le_util.make_or_verify_dir(CONFIG.WORK_DIR, 0o755)
|
||||
le_util.make_or_verify_dir(CONFIG.BACKUP_DIR, 0o755)
|
||||
|
||||
|
||||
def case_i(string):
|
||||
"""Returns case insensitive regex.
|
||||
|
||||
@@ -1559,6 +1671,15 @@ def get_file_path(vhost_path):
|
||||
return avail_fp
|
||||
|
||||
|
||||
def get_aug_path(file_path):
|
||||
"""Return augeas path for full filepath.
|
||||
|
||||
:param str file_path: Full filepath
|
||||
|
||||
"""
|
||||
return "/files%s" % file_path
|
||||
|
||||
|
||||
def strip_dir(path):
|
||||
"""Returns directory of file path.
|
||||
|
||||
@@ -1578,51 +1699,14 @@ def strip_dir(path):
|
||||
return ""
|
||||
|
||||
|
||||
def dvsni_get_cert_file(nonce):
|
||||
"""Returns standardized name for challenge certificate.
|
||||
|
||||
:param str nonce: hex form of nonce
|
||||
|
||||
:returns: certificate file name
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
return CONFIG.WORK_DIR + nonce + ".crt"
|
||||
|
||||
|
||||
def get_config_text(nonce, ip_addrs, dvsni_key_file):
|
||||
"""Chocolate virtual server configuration text
|
||||
|
||||
:param str nonce: hex form of nonce
|
||||
:param str ip_addrs: addresses of challenged domain
|
||||
:param str dvsni_key_file: Path to key file
|
||||
|
||||
:returns: virtual host configuration text
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
return ("<VirtualHost " + " ".join(ip_addrs) + "> \n"
|
||||
"ServerName " + nonce + CONFIG.INVALID_EXT + " \n"
|
||||
"UseCanonicalName on \n"
|
||||
"SSLStrictSNIVHostCheck on \n"
|
||||
"\n"
|
||||
"LimitRequestBody 1048576 \n"
|
||||
"\n"
|
||||
"Include " + CONFIG.OPTIONS_SSL_CONF + " \n"
|
||||
"SSLCertificateFile " + dvsni_get_cert_file(nonce) + " \n"
|
||||
"SSLCertificateKeyFile " + dvsni_key_file + " \n"
|
||||
"\n"
|
||||
"DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n"
|
||||
"</VirtualHost> \n\n")
|
||||
|
||||
|
||||
def dvsni_gen_ext(dvsni_r, dvsni_s):
|
||||
"""Generates z extension to be placed in certificate extension.
|
||||
|
||||
:param bytearray dvsni_r: DVSNI r value
|
||||
:param bytearray dvsni_s: DVSNI s value
|
||||
|
||||
result: returns z + CONFIG.INVALID_EXT
|
||||
:returns: z + CONFIG.INVALID_EXT
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
z_base = hashlib.new('sha256')
|
||||
@@ -1640,7 +1724,7 @@ def main():
|
||||
logger.setLogLevel(logger.DEBUG)
|
||||
|
||||
# for v in config.vhosts:
|
||||
# print v.file
|
||||
# print v.filep
|
||||
# print v.addrs
|
||||
# for name in v.names:
|
||||
# print name
|
||||
@@ -1678,7 +1762,7 @@ def main():
|
||||
# for vh in config.vhosts:
|
||||
# if not vh.addrs:
|
||||
# print vh.names
|
||||
# print vh.file
|
||||
# print vh.filep
|
||||
# if vh.addrs[0] == "23.20.47.131:80":
|
||||
# print "Here we go"
|
||||
# ssl_vh = config.make_vhost_ssl(vh)
|
||||
|
||||
@@ -17,10 +17,29 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
.. todo:: Fix generic exception handling.
|
||||
|
||||
:ivar aug: Augeas object
|
||||
:type aug: :class:`augeas.Augeas`
|
||||
|
||||
:ivar str save_notes: Human-readable configuration change notes
|
||||
:ivar dict direc: dictionary containing save directory paths
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, direc=None):
|
||||
"""Initialize Augeas Configurator.
|
||||
|
||||
:param dict direc: location of save directories
|
||||
(used mostly for testing)
|
||||
|
||||
"""
|
||||
super(AugeasConfigurator, self).__init__()
|
||||
|
||||
if not direc:
|
||||
direc = {"backup": CONFIG.BACKUP_DIR,
|
||||
"temp": CONFIG.TEMP_CHECKPOINT_DIR,
|
||||
"progress": CONFIG.IN_PROGRESS_DIR}
|
||||
|
||||
self.direc = direc
|
||||
# TODO: this instantiation can be optimized to only load
|
||||
# relevant files - I believe -> NO_MODL_AUTOLOAD
|
||||
# Set Augeas flags to save backup
|
||||
@@ -68,7 +87,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
try:
|
||||
# This is a noop save
|
||||
self.aug.save()
|
||||
except:
|
||||
except (RuntimeError, IOError):
|
||||
# Check for the root of save problems
|
||||
new_errs = self.aug.match("/augeas//error")
|
||||
# logger.error("During Save - " + mod_conf)
|
||||
@@ -105,12 +124,12 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
# Create Checkpoint
|
||||
if temporary:
|
||||
self.add_to_checkpoint(CONFIG.TEMP_CHECKPOINT_DIR, save_files)
|
||||
self.add_to_checkpoint(self.direc["temp"], save_files)
|
||||
else:
|
||||
self.add_to_checkpoint(CONFIG.IN_PROGRESS_DIR, save_files)
|
||||
self.add_to_checkpoint(self.direc["progress"], save_files)
|
||||
|
||||
if title and not temporary and os.path.isdir(CONFIG.IN_PROGRESS_DIR):
|
||||
success = self._finalize_checkpoint(CONFIG.IN_PROGRESS_DIR, title)
|
||||
if title and not temporary and os.path.isdir(self.direc["progress"]):
|
||||
success = self._finalize_checkpoint(self.direc["progress"], title)
|
||||
if not success:
|
||||
# This should never happen
|
||||
# This will be hopefully be cleaned up on the recovery
|
||||
@@ -130,12 +149,12 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
for all saves with temporary=True
|
||||
|
||||
"""
|
||||
if os.path.isdir(CONFIG.TEMP_CHECKPOINT_DIR):
|
||||
result = self._recover_checkpoint(CONFIG.TEMP_CHECKPOINT_DIR)
|
||||
if os.path.isdir(self.direc["temp"]):
|
||||
result = self._recover_checkpoint(self.direc["temp"])
|
||||
if result != 0:
|
||||
# We have a partial or incomplete recovery
|
||||
logger.fatal("Incomplete or failed recovery for "
|
||||
"%s" % CONFIG.TEMP_CHECKPOINT_DIR)
|
||||
"%s" % self.direc["temp"])
|
||||
sys.exit(67)
|
||||
# Remember to reload Augeas
|
||||
self.aug.load()
|
||||
@@ -148,22 +167,22 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
"""
|
||||
try:
|
||||
rollback = int(rollback)
|
||||
except:
|
||||
except ValueError:
|
||||
logger.error("Rollback argument must be a positive integer")
|
||||
# Sanity check input
|
||||
if rollback < 1:
|
||||
logger.error("Rollback argument must be a positive integer")
|
||||
return
|
||||
|
||||
backups = os.listdir(CONFIG.BACKUP_DIR)
|
||||
backups = os.listdir(self.direc["backup"])
|
||||
backups.sort()
|
||||
|
||||
if len(backups) < rollback:
|
||||
logger.error(("Unable to rollback %d checkpoints, only "
|
||||
"%d exist") % (rollback, len(backups)))
|
||||
"%d exist") % (rollback, len(backups)))
|
||||
|
||||
while rollback > 0 and backups:
|
||||
cp_dir = CONFIG.BACKUP_DIR + backups.pop()
|
||||
cp_dir = self.direc["backup"] + backups.pop()
|
||||
result = self._recover_checkpoint(cp_dir)
|
||||
if result != 0:
|
||||
logger.fatal("Failed to load checkpoint during rollback")
|
||||
@@ -182,7 +201,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
called.
|
||||
|
||||
"""
|
||||
backups = os.listdir(CONFIG.BACKUP_DIR)
|
||||
backups = os.listdir(self.direc["backup"])
|
||||
backups.sort(reverse=True)
|
||||
|
||||
if not backups:
|
||||
@@ -193,31 +212,29 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
try:
|
||||
for bkup in backups:
|
||||
float(bkup)
|
||||
except:
|
||||
assert False, "Invalid files in %s" % CONFIG.BACKUP_DIR
|
||||
except ValueError:
|
||||
assert False, "Invalid files in %s" % self.direc["backup"]
|
||||
|
||||
for bkup in backups:
|
||||
print time.ctime(float(bkup))
|
||||
with open(
|
||||
CONFIG.BACKUP_DIR + bkup + "/CHANGES_SINCE") as changes_fd:
|
||||
cur_dir = self.direc["backup"] + bkup
|
||||
with open(os.path.join(cur_dir, "CHANGES_SINCE")) as changes_fd:
|
||||
print changes_fd.read()
|
||||
|
||||
print "Affected files:"
|
||||
with open(
|
||||
CONFIG.BACKUP_DIR + bkup + "/FILEPATHS") as paths_fd:
|
||||
with open(os.path.join(cur_dir, "FILEPATHS")) as paths_fd:
|
||||
filepaths = paths_fd.read().splitlines()
|
||||
for path in filepaths:
|
||||
print " %s" % path
|
||||
|
||||
try:
|
||||
with open(
|
||||
CONFIG.BACKUP_DIR + bkup + "/NEW_FILES") as new_fd:
|
||||
with open(os.path.join(cur_dir, "NEW_FILES")) as new_fd:
|
||||
print "New Configuration Files:"
|
||||
filepaths = new_fd.read().splitlines()
|
||||
for path in filepaths:
|
||||
print " %s" % path
|
||||
except:
|
||||
pass
|
||||
except (IOError, OSError) as exc:
|
||||
print exc
|
||||
print ""
|
||||
|
||||
def add_to_checkpoint(self, cp_dir, save_files):
|
||||
@@ -227,7 +244,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
:param set save_files: set of files to save
|
||||
|
||||
"""
|
||||
le_util.make_or_verify_dir(cp_dir, 0o755)
|
||||
le_util.make_or_verify_dir(cp_dir, 0o755, os.geteuid())
|
||||
|
||||
existing_filepaths = []
|
||||
op_fd = None
|
||||
@@ -275,8 +292,8 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
shutil.copy2(os.path.join(
|
||||
cp_dir,
|
||||
os.path.basename(path) + '_' + str(idx)),
|
||||
path)
|
||||
except:
|
||||
path)
|
||||
except (IOError, OSError):
|
||||
# This file is required in all checkpoints.
|
||||
logger.error("Unable to recover files from %s" % cp_dir)
|
||||
return 1
|
||||
@@ -286,7 +303,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
try:
|
||||
shutil.rmtree(cp_dir)
|
||||
except:
|
||||
except OSError:
|
||||
logger.error("Unable to remove directory: %s" % cp_dir)
|
||||
return -1
|
||||
|
||||
@@ -301,7 +318,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
:rtype: bool, str
|
||||
|
||||
"""
|
||||
temp_path = "%sFILEPATHS" % CONFIG.TEMP_CHECKPOINT_DIR
|
||||
temp_path = "%sFILEPATHS" % self.direc["temp"]
|
||||
if os.path.isfile(temp_path):
|
||||
with open(temp_path, 'r') as protected_fd:
|
||||
protected_files = protected_fd.read().splitlines()
|
||||
@@ -327,22 +344,22 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
"""
|
||||
if temporary:
|
||||
cp_dir = CONFIG.TEMP_CHECKPOINT_DIR
|
||||
cp_dir = self.direc["temp"]
|
||||
else:
|
||||
cp_dir = CONFIG.IN_PROGRESS_DIR
|
||||
cp_dir = self.direc["progress"]
|
||||
|
||||
le_util.make_or_verify_dir(cp_dir)
|
||||
try:
|
||||
with open(os.path.join(cp_dir, "NEW_FILES"), 'a') as new_fd:
|
||||
for file_path in files:
|
||||
new_fd.write("%s\n" % file_path)
|
||||
except:
|
||||
except (IOError, OSError):
|
||||
logger.error("ERROR: Unable to register file creation")
|
||||
|
||||
def recovery_routine(self):
|
||||
"""Revert all previously modified files.
|
||||
|
||||
First, any changes found in CONFIG.TEMP_CHECKPOINT_DIR are removed,
|
||||
First, any changes found in self.direc["temp"] are removed,
|
||||
then IN_PROGRESS changes are removed The order is important.
|
||||
IN_PROGRESS is unable to add files that are already added by a TEMP
|
||||
change. Thus TEMP must be rolled back first because that will be the
|
||||
@@ -350,14 +367,14 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
"""
|
||||
self.revert_challenge_config()
|
||||
if os.path.isdir(CONFIG.IN_PROGRESS_DIR):
|
||||
result = self._recover_checkpoint(CONFIG.IN_PROGRESS_DIR)
|
||||
if os.path.isdir(self.direc["progress"]):
|
||||
result = self._recover_checkpoint(self.direc["progress"])
|
||||
if result != 0:
|
||||
# We have a partial or incomplete recovery
|
||||
# Not as egregious
|
||||
# TODO: Additional tests? recovery
|
||||
logger.fatal("Incomplete or failed recovery for %s" %
|
||||
CONFIG.IN_PROGRESS_DIR)
|
||||
self.direc["progress"])
|
||||
sys.exit(68)
|
||||
|
||||
# Need to reload configuration after these changes take effect
|
||||
@@ -390,7 +407,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
"File: %s - Could not be found to be deleted\n"
|
||||
"Program was probably shut down unexpectedly, "
|
||||
"in which case this is not a problem") % path)
|
||||
except IOError:
|
||||
except (IOError, OSError):
|
||||
logger.fatal(
|
||||
"Unable to remove filepaths contained within %s" % file_list)
|
||||
sys.exit(41)
|
||||
@@ -411,7 +428,7 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
final_dir = os.path.join(CONFIG.BACKUP_DIR, str(time.time()))
|
||||
final_dir = os.path.join(self.direc["backup"], str(time.time()))
|
||||
changes_since_path = os.path.join(cp_dir, "CHANGES_SINCE")
|
||||
changes_since_tmp_path = os.path.join(cp_dir, "CHANGES_SINCE.tmp")
|
||||
|
||||
@@ -423,12 +440,12 @@ class AugeasConfigurator(configurator.Configurator):
|
||||
|
||||
shutil.move(changes_since_tmp_path, changes_since_path)
|
||||
|
||||
except:
|
||||
except (IOError, OSError):
|
||||
logger.error("Unable to finalize checkpoint - adding title")
|
||||
return False
|
||||
try:
|
||||
os.rename(cp_dir, final_dir)
|
||||
except:
|
||||
except OSError:
|
||||
logger.error("Unable to finalize checkpoint, %s -> %s" %
|
||||
(cp_dir, final_dir))
|
||||
return False
|
||||
|
||||
@@ -418,7 +418,7 @@ class Client(object):
|
||||
cert_chain_abspath)
|
||||
# Enable any vhost that was issued to, but not enabled
|
||||
if not host.enabled:
|
||||
logger.info("Enabling Site " + host.file)
|
||||
logger.info("Enabling Site " + host.filep)
|
||||
self.config.enable_site(host)
|
||||
|
||||
# sites may have been enabled / final cleanup
|
||||
@@ -564,7 +564,8 @@ class Client(object):
|
||||
"""
|
||||
for ssl_vh in vhost:
|
||||
success, redirect_vhost = self.config.enable_redirect(ssl_vh)
|
||||
logger.info("\nRedirect vhost: " + redirect_vhost.file +
|
||||
# pylint: disable=maybe-no-member
|
||||
logger.info("\nRedirect vhost: " + redirect_vhost.filep +
|
||||
" - " + str(success))
|
||||
# If successful, make sure redirect site is enabled
|
||||
if success:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.. note:: This challenge has not been implemented into the project yet
|
||||
|
||||
"""
|
||||
import dialog
|
||||
import display
|
||||
|
||||
from letsencrypt.client import challenge
|
||||
|
||||
@@ -20,7 +20,7 @@ class RecoveryToken(challenge.Challenge):
|
||||
self.token = ""
|
||||
|
||||
def perform(self, quiet=True):
|
||||
cancel, self.token = dialog.generic_input(
|
||||
cancel, self.token = display.generic_input(
|
||||
"Please Input Recovery Token: ")
|
||||
return cancel != 1
|
||||
|
||||
|
||||
1
letsencrypt/client/tests/__init__.py
Normal file
1
letsencrypt/client/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Let's Encrypt Tests"""
|
||||
310
letsencrypt/client/tests/apache_configurator_test.py
Normal file
310
letsencrypt/client/tests/apache_configurator_test.py
Normal file
@@ -0,0 +1,310 @@
|
||||
"""A series of unit tests for the Apache Configurator."""
|
||||
|
||||
import mock
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from letsencrypt.client import apache_configurator
|
||||
from letsencrypt.client import CONFIG
|
||||
from letsencrypt.client import display
|
||||
from letsencrypt.client import errors
|
||||
from letsencrypt.client import logger
|
||||
|
||||
# pylint: disable=no-member
|
||||
UBUNTU_CONFIGS = pkg_resources.resource_filename(
|
||||
"letsencrypt.client.tests", "testdata/debian_apache_2_4")
|
||||
|
||||
TEMP_DIR = ""
|
||||
CONFIG_DIR = ""
|
||||
WORK_DIR = ""
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def setUpModule():
|
||||
"""Run once before all unittests."""
|
||||
|
||||
global TEMP_DIR, CONFIG_DIR, WORK_DIR
|
||||
|
||||
logger.setLogger(logger.FileLogger(sys.stdout))
|
||||
logger.setLogLevel(logger.INFO)
|
||||
display.set_display(display.NcursesDisplay())
|
||||
|
||||
TEMP_DIR = tempfile.mkdtemp("temp")
|
||||
CONFIG_DIR = tempfile.mkdtemp("config")
|
||||
WORK_DIR = tempfile.mkdtemp("work")
|
||||
|
||||
shutil.copytree(UBUNTU_CONFIGS,
|
||||
os.path.join(TEMP_DIR, "debian_apache_2_4"), symlinks=True)
|
||||
TEMP_DIR = os.path.join(TEMP_DIR, "debian_apache_2_4")
|
||||
|
||||
temp_options = pkg_resources.resource_filename(
|
||||
"letsencrypt.client", os.path.basename(CONFIG.OPTIONS_SSL_CONF))
|
||||
shutil.copyfile(temp_options, os.path.join(CONFIG_DIR, "options-ssl.conf"))
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def tearDownModule():
|
||||
"""Run once after all unittests."""
|
||||
|
||||
shutil.rmtree(TEMP_DIR)
|
||||
shutil.rmtree(CONFIG_DIR)
|
||||
shutil.rmtree(WORK_DIR)
|
||||
|
||||
|
||||
class TwoVhost80(unittest.TestCase):
|
||||
"""Standard two http vhosts that are well configured."""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Run before each and every test."""
|
||||
|
||||
with mock.patch("letsencrypt.client.apache_configurator."
|
||||
"subprocess.Popen") as mock_popen:
|
||||
# This just states that the ssl module is already loaded
|
||||
mock_popen.return_value = MyPopen(("ssl_module", ""))
|
||||
|
||||
# Final slash is currently important
|
||||
self.config_path = os.path.join(TEMP_DIR, "two_vhost_80/apache2/")
|
||||
self.ssl_options = os.path.join(CONFIG_DIR, "options-ssl.conf")
|
||||
backups = os.path.join(WORK_DIR, "backups")
|
||||
|
||||
self.config = apache_configurator.ApacheConfigurator(
|
||||
self.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},
|
||||
self.ssl_options,
|
||||
(2, 4, 7))
|
||||
|
||||
self.aug_path = "/files" + self.config_path
|
||||
|
||||
prefix = os.path.join(TEMP_DIR, "two_vhost_80/apache2/sites-available/")
|
||||
aug_pre = "/files" + prefix
|
||||
self.vh_truth = []
|
||||
self.vh_truth.append(apache_configurator.VH(
|
||||
os.path.join(prefix + "encryption-example.conf"),
|
||||
os.path.join(aug_pre, "encryption-example.conf/VirtualHost"),
|
||||
["*:80"], False, True))
|
||||
self.vh_truth.append(apache_configurator.VH(
|
||||
os.path.join(prefix, "default-ssl.conf"),
|
||||
os.path.join(aug_pre, "default-ssl.conf/IfModule/VirtualHost"),
|
||||
["_default_:443"], True, False))
|
||||
self.vh_truth.append(apache_configurator.VH(
|
||||
os.path.join(prefix, "000-default.conf"),
|
||||
os.path.join(aug_pre, "000-default.conf/VirtualHost"),
|
||||
["*:80"], False, True))
|
||||
self.vh_truth.append(apache_configurator.VH(
|
||||
os.path.join(prefix, "letsencrypt.conf"),
|
||||
os.path.join(aug_pre, "letsencrypt.conf/VirtualHost"),
|
||||
["*:80"], False, True))
|
||||
self.vh_truth[0].add_name("encryption-example.demo")
|
||||
self.vh_truth[2].add_name("ip-172-30-0-17")
|
||||
self.vh_truth[3].add_name("letsencrypt.demo")
|
||||
|
||||
# pylint: disable=protected-access
|
||||
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")
|
||||
self.config._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):
|
||||
"""test get_all_names."""
|
||||
names = self.config.get_all_names()
|
||||
self.assertEqual(set(names), set(
|
||||
['letsencrypt.demo', 'encryption-example.demo', 'ip-172-30-0-17']))
|
||||
|
||||
def test_find_directive(self):
|
||||
"""test find_directive."""
|
||||
test = self.config.find_directive(
|
||||
apache_configurator.case_i("Listen"), "443")
|
||||
# This will only look in enabled hosts
|
||||
test2 = self.config.find_directive(
|
||||
apache_configurator.case_i("documentroot"))
|
||||
self.assertEqual(len(test), 2)
|
||||
self.assertEqual(len(test2), 3)
|
||||
|
||||
def test_get_virtual_hosts(self):
|
||||
"""inefficient get_virtual_hosts check."""
|
||||
vhs = self.config.get_virtual_hosts()
|
||||
self.assertTrue(len(vhs) == 4)
|
||||
found = 0
|
||||
for vhost in vhs:
|
||||
for truth in self.vh_truth:
|
||||
if vhost == truth:
|
||||
found += 1
|
||||
break
|
||||
|
||||
self.assertEqual(found, 4)
|
||||
|
||||
def test_is_site_enabled(self):
|
||||
"""test is_site_enabled"""
|
||||
self.assertTrue(self.config.is_site_enabled(self.vh_truth[0].filep))
|
||||
self.assertTrue(not self.config.is_site_enabled(self.vh_truth[1].filep))
|
||||
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):
|
||||
"""test add_dir."""
|
||||
aug_default = "/files" + self.config.location["default"]
|
||||
self.config.add_dir(
|
||||
aug_default, "AddDirective", "test")
|
||||
|
||||
self.assertTrue(
|
||||
self.config.find_directive("AddDirective", "test", aug_default))
|
||||
|
||||
def test_deploy_cert(self):
|
||||
"""This test modifies the default-ssl vhost SSL directives."""
|
||||
self.config.deploy_cert(
|
||||
self.vh_truth[1],
|
||||
"example/cert.pem", "example/key.pem", "example/cert_chain.pem")
|
||||
|
||||
loc_cert = self.config.find_directive(
|
||||
apache_configurator.case_i("sslcertificatefile"),
|
||||
re.escape("example/cert.pem"), self.vh_truth[1].path)
|
||||
loc_key = self.config.find_directive(
|
||||
apache_configurator.case_i("sslcertificateKeyfile"),
|
||||
re.escape("example/key.pem"), self.vh_truth[1].path)
|
||||
loc_chain = self.config.find_directive(
|
||||
apache_configurator.case_i("SSLCertificateChainFile"),
|
||||
re.escape("example/cert_chain.pem"), self.vh_truth[1].path)
|
||||
|
||||
# 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.vh_truth[1].filep)
|
||||
|
||||
self.assertEqual(len(loc_key), 1)
|
||||
self.assertEqual(apache_configurator.get_file_path(loc_key[0]),
|
||||
self.vh_truth[1].filep)
|
||||
|
||||
self.assertTrue(len(loc_chain), 1)
|
||||
self.assertTrue(apache_configurator.get_file_path(loc_chain[0]),
|
||||
self.vh_truth[1].filep)
|
||||
|
||||
def test_is_name_vhost(self):
|
||||
"""test is_name_vhost."""
|
||||
self.assertTrue(self.config.is_name_vhost("*:80"))
|
||||
self.config.version = (2, 2)
|
||||
self.assertFalse(self.config.is_name_vhost("*:80"))
|
||||
|
||||
def test_add_name_vhost(self):
|
||||
"""test add_name_vhost."""
|
||||
self.config.add_name_vhost("*:443")
|
||||
# self.config.save(temporary=True)
|
||||
self.assertTrue(self.config.find_directive(
|
||||
"NameVirtualHost", re.escape("*:443")))
|
||||
|
||||
# pylint: disable=protected-access
|
||||
def test_add_dir_to_ifmodssl(self):
|
||||
"""test _add_dir_to_ifmodssl.
|
||||
|
||||
Path must be valid before attempting to add to augeas
|
||||
|
||||
"""
|
||||
self.config._add_dir_to_ifmodssl(
|
||||
"/files" + self.config.location["default"], "FakeDirective", "123")
|
||||
|
||||
matches = self.config.find_directive("FakeDirective", "123")
|
||||
|
||||
self.assertEqual(len(matches), 1)
|
||||
self.assertTrue("IfModule" in matches[0])
|
||||
|
||||
def test_make_vhost_ssl(self):
|
||||
"""test make_vhost_ssl."""
|
||||
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
||||
|
||||
self.assertTrue(
|
||||
ssl_vhost.filep ==
|
||||
os.path.join(self.config_path, "sites-available",
|
||||
"encryption-example-le-ssl.conf"))
|
||||
|
||||
self.assertTrue(ssl_vhost.path ==
|
||||
"/files" + ssl_vhost.filep + "/IfModule/VirtualHost")
|
||||
self.assertTrue(ssl_vhost.addrs == ["*:443"])
|
||||
self.assertTrue(ssl_vhost.names == ["encryption-example.demo"])
|
||||
self.assertTrue(ssl_vhost.ssl)
|
||||
self.assertFalse(ssl_vhost.enabled)
|
||||
|
||||
self.assertTrue(self.config.find_directive(
|
||||
"SSLCertificateFile", None, ssl_vhost.path))
|
||||
self.assertTrue(self.config.find_directive(
|
||||
"SSLCertificateKeyFile", None, ssl_vhost.path))
|
||||
self.assertTrue(self.config.find_directive(
|
||||
"Include", self.ssl_options, ssl_vhost.path))
|
||||
|
||||
self.assertEqual(self.config.is_name_vhost(self.vh_truth[0]),
|
||||
self.config.is_name_vhost(ssl_vhost))
|
||||
|
||||
self.assertEqual(len(self.config.vhosts), 5)
|
||||
|
||||
@mock.patch("letsencrypt.client.apache_configurator."
|
||||
"subprocess.Popen")
|
||||
def test_get_version(self, mock_popen):
|
||||
"""test get_version."""
|
||||
mock_popen.return_value = MyPopen(
|
||||
("Server Version: Apache/2.4.2 (Debian)", ""))
|
||||
self.assertEqual(self.config.get_version(), (2, 4, 2))
|
||||
|
||||
mock_popen.return_value = MyPopen(
|
||||
("Server Version: Apache/2 (Linux)", ""))
|
||||
self.assertEqual(self.config.get_version(), tuple([2]))
|
||||
|
||||
mock_popen.return_value = MyPopen(
|
||||
("Server Version: Apache (Debian)", ""))
|
||||
self.assertRaises(
|
||||
errors.LetsEncryptConfiguratorError, self.config.get_version)
|
||||
|
||||
mock_popen.return_value = MyPopen(
|
||||
("Server Version: Apache/2.3\n Apache/2.4.7", ""))
|
||||
self.assertRaises(
|
||||
errors.LetsEncryptConfiguratorError, self.config.get_version)
|
||||
|
||||
mock_popen.side_effect = OSError("Can't find program")
|
||||
self.assertRaises(
|
||||
errors.LetsEncryptConfiguratorError, self.config.get_version)
|
||||
|
||||
# def _verify_redirect(self, config_path):
|
||||
# """Verifies that the vhost contains the REWRITE."""
|
||||
# with open(config_path, 'r') as config_fd:
|
||||
# conf = config_fd.read()
|
||||
|
||||
# return CONFIG.REWRITE_HTTPS_ARGS[1] in conf
|
||||
|
||||
|
||||
# def debug_file(filepath):
|
||||
# """Print out the file."""
|
||||
# with open(filepath, 'r')as file_d:
|
||||
# print file_d.read()
|
||||
|
||||
|
||||
# I am sure there is a cleaner way to do this... but it works
|
||||
# pylint: disable=too-few-public-methods
|
||||
class MyPopen(object):
|
||||
"""Made for mock popen object."""
|
||||
def __init__(self, tup):
|
||||
self.tup = tup
|
||||
|
||||
def communicate(self): # pylint: disable=no-self-use
|
||||
"""Simply return that ssl_module is in output."""
|
||||
return self.tup
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
198
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf
vendored
Normal file
198
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/apache2.conf
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
# This is the main Apache server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See http://httpd.apache.org/docs/2.4/ for detailed information about
|
||||
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
|
||||
# hints.
|
||||
#
|
||||
#
|
||||
# Summary of how the Apache 2 configuration works in Debian:
|
||||
# The Apache 2 web server configuration in Debian is quite different to
|
||||
# upstream's suggested way to configure the web server. This is because Debian's
|
||||
# default Apache2 installation attempts to make adding and removing modules,
|
||||
# virtual hosts, and extra configuration directives as flexible as possible, in
|
||||
# order to make automating the changes and administering the server as easy as
|
||||
# possible.
|
||||
|
||||
# It is split into several files forming the configuration hierarchy outlined
|
||||
# below, all located in the /etc/apache2/ directory:
|
||||
#
|
||||
# /etc/apache2/
|
||||
# |-- apache2.conf
|
||||
# | `-- ports.conf
|
||||
# |-- mods-enabled
|
||||
# | |-- *.load
|
||||
# | `-- *.conf
|
||||
# |-- conf-enabled
|
||||
# | `-- *.conf
|
||||
# `-- sites-enabled
|
||||
# `-- *.conf
|
||||
#
|
||||
#
|
||||
# * apache2.conf is the main configuration file (this file). It puts the pieces
|
||||
# together by including all remaining configuration files when starting up the
|
||||
# web server.
|
||||
#
|
||||
# * ports.conf is always included from the main configuration file. It is
|
||||
# supposed to determine listening ports for incoming connections which can be
|
||||
# customized anytime.
|
||||
#
|
||||
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
|
||||
# directories contain particular configuration snippets which manage modules,
|
||||
# global configuration fragments, or virtual host configurations,
|
||||
# respectively.
|
||||
#
|
||||
# They are activated by symlinking available configuration files from their
|
||||
# respective *-available/ counterparts. These should be managed by using our
|
||||
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
|
||||
# their respective man pages for detailed information.
|
||||
#
|
||||
# * The binary is called apache2. Due to the use of environment variables, in
|
||||
# the default configuration, apache2 needs to be started/stopped with
|
||||
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
|
||||
# work with the default configuration.
|
||||
|
||||
|
||||
# Global configuration
|
||||
|
||||
#
|
||||
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
|
||||
#
|
||||
Mutex file:${APACHE_LOCK_DIR} default
|
||||
|
||||
#
|
||||
# PidFile: The file in which the server should record its process
|
||||
# identification number when it starts.
|
||||
# This needs to be set in /etc/apache2/envvars
|
||||
#
|
||||
PidFile ${APACHE_PID_FILE}
|
||||
|
||||
#
|
||||
# Timeout: The number of seconds before receives and sends time out.
|
||||
#
|
||||
Timeout 300
|
||||
|
||||
#
|
||||
# KeepAlive: Whether or not to allow persistent connections (more than
|
||||
# one request per connection). Set to "Off" to deactivate.
|
||||
#
|
||||
KeepAlive On
|
||||
|
||||
#
|
||||
# MaxKeepAliveRequests: The maximum number of requests to allow
|
||||
# during a persistent connection. Set to 0 to allow an unlimited amount.
|
||||
# We recommend you leave this number high, for maximum performance.
|
||||
#
|
||||
MaxKeepAliveRequests 100
|
||||
|
||||
#
|
||||
# KeepAliveTimeout: Number of seconds to wait for the next request from the
|
||||
# same client on the same connection.
|
||||
#
|
||||
KeepAliveTimeout 5
|
||||
|
||||
|
||||
# These need to be set in /etc/apache2/envvars
|
||||
User ${APACHE_RUN_USER}
|
||||
Group ${APACHE_RUN_GROUP}
|
||||
|
||||
#
|
||||
# HostnameLookups: Log the names of clients or just their IP addresses
|
||||
# e.g., www.apache.org (on) or 204.62.129.132 (off).
|
||||
# The default is off because it'd be overall better for the net if people
|
||||
# had to knowingly turn this feature on, since enabling it means that
|
||||
# each client request will result in AT LEAST one lookup request to the
|
||||
# nameserver.
|
||||
#
|
||||
HostnameLookups Off
|
||||
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
#
|
||||
# LogLevel: Control the severity of messages logged to the error_log.
|
||||
# Available values: trace8, ..., trace1, debug, info, notice, warn,
|
||||
# error, crit, alert, emerg.
|
||||
# It is also possible to configure the log level for particular modules, e.g.
|
||||
# "LogLevel info ssl:warn"
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
# Include module configuration:
|
||||
IncludeOptional mods-enabled/*.load
|
||||
IncludeOptional mods-enabled/*.conf
|
||||
|
||||
# Include list of ports to listen on
|
||||
Include ports.conf
|
||||
|
||||
|
||||
# Sets the default security model of the Apache2 HTTPD server. It does
|
||||
# not allow access to the root filesystem outside of /usr/share and /var/www.
|
||||
# The former is used by web applications packaged in Debian,
|
||||
# the latter may be used for local directories served by the web server. If
|
||||
# your system is serving content from a sub-directory in /srv you must allow
|
||||
# access here, or in any related virtual host.
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
<Directory /usr/share>
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /var/>
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# AccessFileName: The name of the file to look for in each directory
|
||||
# for additional configuration directives. See also the AllowOverride
|
||||
# directive.
|
||||
#
|
||||
AccessFileName .htaccess
|
||||
|
||||
#
|
||||
# The following lines prevent .htaccess and .htpasswd files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<FilesMatch "^\.ht">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
|
||||
#
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive.
|
||||
#
|
||||
# These deviate from the Common Log Format definitions in that they use %O
|
||||
# (the actual bytes sent including headers) instead of %b (the size of the
|
||||
# requested file), because the latter makes it impossible to detect partial
|
||||
# requests.
|
||||
#
|
||||
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
|
||||
# Use mod_remoteip instead.
|
||||
#
|
||||
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O" common
|
||||
LogFormat "%{Referer}i -> %U" referer
|
||||
LogFormat "%{User-agent}i" agent
|
||||
|
||||
# Include of directories ignores editors' and dpkg's backup files,
|
||||
# see README.Debian for details.
|
||||
|
||||
# Include generic snippets of statements
|
||||
IncludeOptional conf-enabled/*.conf
|
||||
|
||||
# Include the virtual host configurations:
|
||||
IncludeOptional sites-enabled/*.conf
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,4 @@
|
||||
# Define an access log for VirtualHosts that don't define their own logfile
|
||||
CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log vhost_combined
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,31 @@
|
||||
# ServerTokens
|
||||
# This directive configures what you return as the Server HTTP response
|
||||
# Header. The default is 'Full' which sends information about the OS-Type
|
||||
# and compiled in modules.
|
||||
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
|
||||
# where Full conveys the most information, and Prod the least.
|
||||
#ServerTokens Minimal
|
||||
ServerTokens OS
|
||||
#ServerTokens Full
|
||||
|
||||
#
|
||||
# Optionally add a line containing the server version and virtual host
|
||||
# name to server-generated pages (internal error documents, FTP directory
|
||||
# listings, mod_status and mod_info output etc., but not CGI generated
|
||||
# documents or custom error documents).
|
||||
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
|
||||
# Set to one of: On | Off | EMail
|
||||
#ServerSignature Off
|
||||
ServerSignature On
|
||||
|
||||
#
|
||||
# Allow TRACE method
|
||||
#
|
||||
# Set to "extended" to also reflect the request body (only for testing and
|
||||
# diagnostic purposes).
|
||||
#
|
||||
# Set to one of: On | Off | extended
|
||||
TraceEnable Off
|
||||
#TraceEnable On
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,20 @@
|
||||
<IfModule mod_alias.c>
|
||||
<IfModule mod_cgi.c>
|
||||
Define ENABLE_USR_LIB_CGI_BIN
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_cgid.c>
|
||||
Define ENABLE_USR_LIB_CGI_BIN
|
||||
</IfModule>
|
||||
|
||||
<IfDefine ENABLE_USR_LIB_CGI_BIN>
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
<Directory "/usr/lib/cgi-bin">
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
Require all granted
|
||||
</Directory>
|
||||
</IfDefine>
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1 @@
|
||||
../conf-available/other-vhosts-access-log.conf
|
||||
1
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf
vendored
Symbolic link
1
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/conf-enabled/security.conf
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../conf-available/security.conf
|
||||
@@ -0,0 +1 @@
|
||||
../conf-available/serve-cgi-bin.conf
|
||||
28
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars
vendored
Normal file
28
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/envvars
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# envvars - default environment variables for apache2ctl
|
||||
|
||||
# this won't be correct after changing uid
|
||||
unset HOME
|
||||
|
||||
# for supporting multiple apache2 instances
|
||||
if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then
|
||||
SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}"
|
||||
else
|
||||
SUFFIX=
|
||||
fi
|
||||
|
||||
# Since there is no sane way to get the parsed apache2 config in scripts, some
|
||||
# settings are defined via environment variables and then used in apache2ctl,
|
||||
# /etc/init.d/apache2, /etc/logrotate.d/apache2, etc.
|
||||
export APACHE_RUN_USER=www-data
|
||||
export APACHE_RUN_GROUP=www-data
|
||||
# temporary state file location. This might be changed to /run in Wheezy+1
|
||||
export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid
|
||||
export APACHE_RUN_DIR=/var/run/apache2$SUFFIX
|
||||
export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX
|
||||
# Only /var/log/apache2 is handled by /etc/logrotate.d/apache2.
|
||||
export APACHE_LOG_DIR=/var/log/apache2$SUFFIX
|
||||
|
||||
## The locale used by some modules like mod_dav
|
||||
export LANG=C
|
||||
|
||||
export LANG
|
||||
@@ -0,0 +1,89 @@
|
||||
<IfModule mod_ssl.c>
|
||||
|
||||
# Pseudo Random Number Generator (PRNG):
|
||||
# Configure one or more sources to seed the PRNG of the SSL library.
|
||||
# The seed data should be of good random quality.
|
||||
# WARNING! On some platforms /dev/random blocks if not enough entropy
|
||||
# is available. This means you then cannot use the /dev/random device
|
||||
# because it would lead to very long connection times (as long as
|
||||
# it requires to make more entropy available). But usually those
|
||||
# platforms additionally provide a /dev/urandom device which doesn't
|
||||
# block. So, if available, use this one instead. Read the mod_ssl User
|
||||
# Manual for more details.
|
||||
#
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed startup file:/dev/urandom 512
|
||||
SSLRandomSeed connect builtin
|
||||
SSLRandomSeed connect file:/dev/urandom 512
|
||||
|
||||
##
|
||||
## SSL Global Context
|
||||
##
|
||||
## All SSL configuration in this context applies both to
|
||||
## the main server and all SSL-enabled virtual hosts.
|
||||
##
|
||||
|
||||
#
|
||||
# Some MIME-types for downloading Certificates and CRLs
|
||||
#
|
||||
AddType application/x-x509-ca-cert .crt
|
||||
AddType application/x-pkcs7-crl .crl
|
||||
|
||||
# Pass Phrase Dialog:
|
||||
# Configure the pass phrase gathering process.
|
||||
# The filtering dialog program (`builtin' is a internal
|
||||
# terminal dialog) has to provide the pass phrase on stdout.
|
||||
SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase
|
||||
|
||||
# Inter-Process Session Cache:
|
||||
# Configure the SSL Session Cache: First the mechanism
|
||||
# to use and second the expiring timeout (in seconds).
|
||||
# (The mechanism dbm has known memory leaks and should not be used).
|
||||
#SSLSessionCache dbm:${APACHE_RUN_DIR}/ssl_scache
|
||||
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
|
||||
SSLSessionCacheTimeout 300
|
||||
|
||||
# Semaphore:
|
||||
# Configure the path to the mutual exclusion semaphore the
|
||||
# SSL engine uses internally for inter-process synchronization.
|
||||
# (Disabled by default, the global Mutex directive consolidates by default
|
||||
# this)
|
||||
#Mutex file:${APACHE_LOCK_DIR}/ssl_mutex ssl-cache
|
||||
|
||||
|
||||
# SSL Cipher Suite:
|
||||
# List the ciphers that the client is permitted to negotiate. See the
|
||||
# ciphers(1) man page from the openssl package for list of all available
|
||||
# options.
|
||||
# Enable only secure ciphers:
|
||||
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
|
||||
|
||||
# Speed-optimized SSL Cipher configuration:
|
||||
# If speed is your main concern (on busy HTTPS servers e.g.),
|
||||
# you might want to force clients to specific, performance
|
||||
# optimized ciphers. In this case, prepend those ciphers
|
||||
# to the SSLCipherSuite list, and enable SSLHonorCipherOrder.
|
||||
# Caveat: by giving precedence to RC4-SHA and AES128-SHA
|
||||
# (as in the example below), most connections will no longer
|
||||
# have perfect forward secrecy - if the server's key is
|
||||
# compromised, captures of past or future traffic must be
|
||||
# considered compromised, too.
|
||||
#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
|
||||
#SSLHonorCipherOrder on
|
||||
|
||||
# The protocols to enable.
|
||||
# Available values: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2
|
||||
# SSL v2 is no longer supported
|
||||
SSLProtocol all
|
||||
|
||||
# Allow insecure renegotiation with clients which do not yet support the
|
||||
# secure renegotiation protocol. Default: Off
|
||||
#SSLInsecureRenegotiation on
|
||||
|
||||
# Whether to forbid non-SNI clients to access name based virtual hosts.
|
||||
# Default: Off
|
||||
#SSLStrictSNIVHostCheck On
|
||||
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,2 @@
|
||||
# Depends: setenvif mime socache_shmcb
|
||||
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
|
||||
20
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf
vendored
Normal file
20
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/apache2/ports.conf
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# If you just change the port or add more ports here, you will likely also
|
||||
# have to change the VirtualHost statement in
|
||||
# /etc/apache2/sites-enabled/000-default.conf
|
||||
|
||||
Listen 80
|
||||
|
||||
NameVirtualHost *:80
|
||||
|
||||
<IfModule ssl_module>
|
||||
Listen 443
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_gnutls.c>
|
||||
Listen 443
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
<IfModule mod_ssl.c>
|
||||
NameVirtualHost *:443
|
||||
</IfModule>
|
||||
@@ -0,0 +1,11 @@
|
||||
<VirtualHost *:80>
|
||||
# How well does Let's Encrypt work without a ServerName/Alias?
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,38 @@
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost _default_:443>
|
||||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
# SSL Engine Switch:
|
||||
# Enable/Disable SSL for this virtual host.
|
||||
SSLEngine on
|
||||
|
||||
# A self-signed (snakeoil) certificate can be created by installing
|
||||
# the ssl-cert package. See
|
||||
# /usr/share/doc/apache2/README.Debian.gz for more info.
|
||||
# If both key and certificate are stored in the same file, only the
|
||||
# SSLCertificateFile directive is needed.
|
||||
SSLCertificateFile /etc/apache2/certs/letsencrypt-cert_5.pem
|
||||
SSLCertificateKeyFile /etc/apache2/ssl/key-letsencrypt_15.pem
|
||||
|
||||
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||
SSLOptions +StdEnvVars
|
||||
</FilesMatch>
|
||||
<Directory /usr/lib/cgi-bin>
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
|
||||
BrowserMatch "MSIE [2-6]" \
|
||||
nokeepalive ssl-unclean-shutdown \
|
||||
downgrade-1.0 force-response-1.0
|
||||
# MSIE 7 and newer should be able to use keepalive
|
||||
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1 @@
|
||||
../sites-available/000-default.conf
|
||||
1
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/sites
vendored
Normal file
1
letsencrypt/client/tests/testdata/debian_apache_2_4/default_vhost/sites
vendored
Normal file
@@ -0,0 +1 @@
|
||||
sites-available/000-default.conf, default.com
|
||||
196
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf
vendored
Normal file
196
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/apache2.conf
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
# This is the main Apache server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See http://httpd.apache.org/docs/2.4/ for detailed information about
|
||||
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
|
||||
# hints.
|
||||
#
|
||||
#
|
||||
# Summary of how the Apache 2 configuration works in Debian:
|
||||
# The Apache 2 web server configuration in Debian is quite different to
|
||||
# upstream's suggested way to configure the web server. This is because Debian's
|
||||
# default Apache2 installation attempts to make adding and removing modules,
|
||||
# virtual hosts, and extra configuration directives as flexible as possible, in
|
||||
# order to make automating the changes and administering the server as easy as
|
||||
# possible.
|
||||
|
||||
# It is split into several files forming the configuration hierarchy outlined
|
||||
# below, all located in the /etc/apache2/ directory:
|
||||
#
|
||||
# /etc/apache2/
|
||||
# |-- apache2.conf
|
||||
# | `-- ports.conf
|
||||
# |-- mods-enabled
|
||||
# | |-- *.load
|
||||
# | `-- *.conf
|
||||
# |-- conf-enabled
|
||||
# | `-- *.conf
|
||||
# `-- sites-enabled
|
||||
# `-- *.conf
|
||||
#
|
||||
#
|
||||
# * apache2.conf is the main configuration file (this file). It puts the pieces
|
||||
# together by including all remaining configuration files when starting up the
|
||||
# web server.
|
||||
#
|
||||
# * ports.conf is always included from the main configuration file. It is
|
||||
# supposed to determine listening ports for incoming connections which can be
|
||||
# customized anytime.
|
||||
#
|
||||
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
|
||||
# directories contain particular configuration snippets which manage modules,
|
||||
# global configuration fragments, or virtual host configurations,
|
||||
# respectively.
|
||||
#
|
||||
# They are activated by symlinking available configuration files from their
|
||||
# respective *-available/ counterparts. These should be managed by using our
|
||||
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
|
||||
# their respective man pages for detailed information.
|
||||
#
|
||||
# * The binary is called apache2. Due to the use of environment variables, in
|
||||
# the default configuration, apache2 needs to be started/stopped with
|
||||
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
|
||||
# work with the default configuration.
|
||||
|
||||
|
||||
# Global configuration
|
||||
|
||||
#
|
||||
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
|
||||
#
|
||||
Mutex file:${APACHE_LOCK_DIR} default
|
||||
|
||||
#
|
||||
# PidFile: The file in which the server should record its process
|
||||
# identification number when it starts.
|
||||
# This needs to be set in /etc/apache2/envvars
|
||||
#
|
||||
PidFile ${APACHE_PID_FILE}
|
||||
|
||||
#
|
||||
# Timeout: The number of seconds before receives and sends time out.
|
||||
#
|
||||
Timeout 300
|
||||
|
||||
#
|
||||
# KeepAlive: Whether or not to allow persistent connections (more than
|
||||
# one request per connection). Set to "Off" to deactivate.
|
||||
#
|
||||
KeepAlive On
|
||||
|
||||
#
|
||||
# MaxKeepAliveRequests: The maximum number of requests to allow
|
||||
# during a persistent connection. Set to 0 to allow an unlimited amount.
|
||||
# We recommend you leave this number high, for maximum performance.
|
||||
#
|
||||
MaxKeepAliveRequests 100
|
||||
|
||||
#
|
||||
# KeepAliveTimeout: Number of seconds to wait for the next request from the
|
||||
# same client on the same connection.
|
||||
#
|
||||
KeepAliveTimeout 5
|
||||
|
||||
|
||||
# These need to be set in /etc/apache2/envvars
|
||||
User ${APACHE_RUN_USER}
|
||||
Group ${APACHE_RUN_GROUP}
|
||||
|
||||
#
|
||||
# HostnameLookups: Log the names of clients or just their IP addresses
|
||||
# e.g., www.apache.org (on) or 204.62.129.132 (off).
|
||||
# The default is off because it'd be overall better for the net if people
|
||||
# had to knowingly turn this feature on, since enabling it means that
|
||||
# each client request will result in AT LEAST one lookup request to the
|
||||
# nameserver.
|
||||
#
|
||||
HostnameLookups Off
|
||||
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
#
|
||||
# LogLevel: Control the severity of messages logged to the error_log.
|
||||
# Available values: trace8, ..., trace1, debug, info, notice, warn,
|
||||
# error, crit, alert, emerg.
|
||||
# It is also possible to configure the log level for particular modules, e.g.
|
||||
# "LogLevel info ssl:warn"
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
# Include module configuration:
|
||||
IncludeOptional mods-enabled/*.load
|
||||
IncludeOptional mods-enabled/*.conf
|
||||
|
||||
# Include list of ports to listen on
|
||||
Include ports.conf
|
||||
|
||||
|
||||
# Sets the default security model of the Apache2 HTTPD server. It does
|
||||
# not allow access to the root filesystem outside of /usr/share and /var/www.
|
||||
# The former is used by web applications packaged in Debian,
|
||||
# the latter may be used for local directories served by the web server. If
|
||||
# your system is serving content from a sub-directory in /srv you must allow
|
||||
# access here, or in any related virtual host.
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
<Directory /usr/share>
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /var/>
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# AccessFileName: The name of the file to look for in each directory
|
||||
# for additional configuration directives. See also the AllowOverride
|
||||
# directive.
|
||||
#
|
||||
AccessFileName .htaccess
|
||||
|
||||
#
|
||||
# The following lines prevent .htaccess and .htpasswd files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<FilesMatch "^\.ht">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive.
|
||||
#
|
||||
# These deviate from the Common Log Format definitions in that they use %O
|
||||
# (the actual bytes sent including headers) instead of %b (the size of the
|
||||
# requested file), because the latter makes it impossible to detect partial
|
||||
# requests.
|
||||
#
|
||||
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
|
||||
# Use mod_remoteip instead.
|
||||
#
|
||||
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O" common
|
||||
LogFormat "%{Referer}i -> %U" referer
|
||||
LogFormat "%{User-agent}i" agent
|
||||
|
||||
# Include of directories ignores editors' and dpkg's backup files,
|
||||
# see README.Debian for details.
|
||||
|
||||
# Include generic snippets of statements
|
||||
IncludeOptional conf-enabled/*.conf
|
||||
|
||||
# Include the virtual host configurations:
|
||||
IncludeOptional sites-enabled/*.conf
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,4 @@
|
||||
# Define an access log for VirtualHosts that don't define their own logfile
|
||||
CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log vhost_combined
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,35 @@
|
||||
# Changing the following options will not really affect the security of the
|
||||
# server, but might make attacks slightly more difficult in some cases.
|
||||
|
||||
#
|
||||
# ServerTokens
|
||||
# This directive configures what you return as the Server HTTP response
|
||||
# Header. The default is 'Full' which sends information about the OS-Type
|
||||
# and compiled in modules.
|
||||
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
|
||||
# where Full conveys the most information, and Prod the least.
|
||||
#ServerTokens Minimal
|
||||
ServerTokens OS
|
||||
#ServerTokens Full
|
||||
|
||||
#
|
||||
# Optionally add a line containing the server version and virtual host
|
||||
# name to server-generated pages (internal error documents, FTP directory
|
||||
# listings, mod_status and mod_info output etc., but not CGI generated
|
||||
# documents or custom error documents).
|
||||
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
|
||||
# Set to one of: On | Off | EMail
|
||||
#ServerSignature Off
|
||||
ServerSignature On
|
||||
|
||||
#
|
||||
# Allow TRACE method
|
||||
#
|
||||
# Set to "extended" to also reflect the request body (only for testing and
|
||||
# diagnostic purposes).
|
||||
#
|
||||
# Set to one of: On | Off | extended
|
||||
TraceEnable Off
|
||||
#TraceEnable On
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,20 @@
|
||||
<IfModule mod_alias.c>
|
||||
<IfModule mod_cgi.c>
|
||||
Define ENABLE_USR_LIB_CGI_BIN
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_cgid.c>
|
||||
Define ENABLE_USR_LIB_CGI_BIN
|
||||
</IfModule>
|
||||
|
||||
<IfDefine ENABLE_USR_LIB_CGI_BIN>
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
<Directory "/usr/lib/cgi-bin">
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
Require all granted
|
||||
</Directory>
|
||||
</IfDefine>
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1 @@
|
||||
../conf-available/other-vhosts-access-log.conf
|
||||
1
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf
vendored
Symbolic link
1
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/conf-enabled/security.conf
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../conf-available/security.conf
|
||||
@@ -0,0 +1 @@
|
||||
../conf-available/serve-cgi-bin.conf
|
||||
29
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars
vendored
Normal file
29
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/envvars
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# envvars - default environment variables for apache2ctl
|
||||
|
||||
# this won't be correct after changing uid
|
||||
unset HOME
|
||||
|
||||
# for supporting multiple apache2 instances
|
||||
if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then
|
||||
SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}"
|
||||
else
|
||||
SUFFIX=
|
||||
fi
|
||||
|
||||
# Since there is no sane way to get the parsed apache2 config in scripts, some
|
||||
# settings are defined via environment variables and then used in apache2ctl,
|
||||
# /etc/init.d/apache2, /etc/logrotate.d/apache2, etc.
|
||||
export APACHE_RUN_USER=www-data
|
||||
export APACHE_RUN_GROUP=www-data
|
||||
# temporary state file location. This might be changed to /run in Wheezy+1
|
||||
export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid
|
||||
export APACHE_RUN_DIR=/var/run/apache2$SUFFIX
|
||||
export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX
|
||||
# Only /var/log/apache2 is handled by /etc/logrotate.d/apache2.
|
||||
export APACHE_LOG_DIR=/var/log/apache2$SUFFIX
|
||||
|
||||
## The locale used by some modules like mod_dav
|
||||
export LANG=C
|
||||
|
||||
export LANG
|
||||
|
||||
89
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf
vendored
Normal file
89
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/mods-available/ssl.conf
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<IfModule mod_ssl.c>
|
||||
|
||||
# Pseudo Random Number Generator (PRNG):
|
||||
# Configure one or more sources to seed the PRNG of the SSL library.
|
||||
# The seed data should be of good random quality.
|
||||
# WARNING! On some platforms /dev/random blocks if not enough entropy
|
||||
# is available. This means you then cannot use the /dev/random device
|
||||
# because it would lead to very long connection times (as long as
|
||||
# it requires to make more entropy available). But usually those
|
||||
# platforms additionally provide a /dev/urandom device which doesn't
|
||||
# block. So, if available, use this one instead. Read the mod_ssl User
|
||||
# Manual for more details.
|
||||
#
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed startup file:/dev/urandom 512
|
||||
SSLRandomSeed connect builtin
|
||||
SSLRandomSeed connect file:/dev/urandom 512
|
||||
|
||||
##
|
||||
## SSL Global Context
|
||||
##
|
||||
## All SSL configuration in this context applies both to
|
||||
## the main server and all SSL-enabled virtual hosts.
|
||||
##
|
||||
|
||||
#
|
||||
# Some MIME-types for downloading Certificates and CRLs
|
||||
#
|
||||
AddType application/x-x509-ca-cert .crt
|
||||
AddType application/x-pkcs7-crl .crl
|
||||
|
||||
# Pass Phrase Dialog:
|
||||
# Configure the pass phrase gathering process.
|
||||
# The filtering dialog program (`builtin' is a internal
|
||||
# terminal dialog) has to provide the pass phrase on stdout.
|
||||
SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase
|
||||
|
||||
# Inter-Process Session Cache:
|
||||
# Configure the SSL Session Cache: First the mechanism
|
||||
# to use and second the expiring timeout (in seconds).
|
||||
# (The mechanism dbm has known memory leaks and should not be used).
|
||||
#SSLSessionCache dbm:${APACHE_RUN_DIR}/ssl_scache
|
||||
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
|
||||
SSLSessionCacheTimeout 300
|
||||
|
||||
# Semaphore:
|
||||
# Configure the path to the mutual exclusion semaphore the
|
||||
# SSL engine uses internally for inter-process synchronization.
|
||||
# (Disabled by default, the global Mutex directive consolidates by default
|
||||
# this)
|
||||
#Mutex file:${APACHE_LOCK_DIR}/ssl_mutex ssl-cache
|
||||
|
||||
|
||||
# SSL Cipher Suite:
|
||||
# List the ciphers that the client is permitted to negotiate. See the
|
||||
# ciphers(1) man page from the openssl package for list of all available
|
||||
# options.
|
||||
# Enable only secure ciphers:
|
||||
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
|
||||
|
||||
# Speed-optimized SSL Cipher configuration:
|
||||
# If speed is your main concern (on busy HTTPS servers e.g.),
|
||||
# you might want to force clients to specific, performance
|
||||
# optimized ciphers. In this case, prepend those ciphers
|
||||
# to the SSLCipherSuite list, and enable SSLHonorCipherOrder.
|
||||
# Caveat: by giving precedence to RC4-SHA and AES128-SHA
|
||||
# (as in the example below), most connections will no longer
|
||||
# have perfect forward secrecy - if the server's key is
|
||||
# compromised, captures of past or future traffic must be
|
||||
# considered compromised, too.
|
||||
#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
|
||||
#SSLHonorCipherOrder on
|
||||
|
||||
# The protocols to enable.
|
||||
# Available values: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2
|
||||
# SSL v2 is no longer supported
|
||||
SSLProtocol all
|
||||
|
||||
# Allow insecure renegotiation with clients which do not yet support the
|
||||
# secure renegotiation protocol. Default: Off
|
||||
#SSLInsecureRenegotiation on
|
||||
|
||||
# Whether to forbid non-SNI clients to access name based virtual hosts.
|
||||
# Default: Off
|
||||
#SSLStrictSNIVHostCheck On
|
||||
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,2 @@
|
||||
# Depends: setenvif mime socache_shmcb
|
||||
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
|
||||
15
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf
vendored
Normal file
15
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/apache2/ports.conf
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# If you just change the port or add more ports here, you will likely also
|
||||
# have to change the VirtualHost statement in
|
||||
# /etc/apache2/sites-enabled/000-default.conf
|
||||
|
||||
Listen 80
|
||||
|
||||
<IfModule ssl_module>
|
||||
Listen 443
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_gnutls.c>
|
||||
Listen 443
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,12 @@
|
||||
<VirtualHost *:80>
|
||||
|
||||
ServerName ip-172-30-0-17
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,40 @@
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost _default_:443>
|
||||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
# SSL Engine Switch:
|
||||
# Enable/Disable SSL for this virtual host.
|
||||
SSLEngine on
|
||||
|
||||
# A self-signed (snakeoil) certificate can be created by installing
|
||||
# the ssl-cert package. See
|
||||
# /usr/share/doc/apache2/README.Debian.gz for more info.
|
||||
# If both key and certificate are stored in the same file, only the
|
||||
# SSLCertificateFile directive is needed.
|
||||
SSLCertificateFile /etc/apache2/certs/letsencrypt-cert_5.pem
|
||||
SSLCertificateKeyFile /etc/apache2/ssl/key-letsencrypt_15.pem
|
||||
|
||||
|
||||
#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
|
||||
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||
SSLOptions +StdEnvVars
|
||||
</FilesMatch>
|
||||
<Directory /usr/lib/cgi-bin>
|
||||
SSLOptions +StdEnvVars
|
||||
</Directory>
|
||||
|
||||
BrowserMatch "MSIE [2-6]" \
|
||||
nokeepalive ssl-unclean-shutdown \
|
||||
downgrade-1.0 force-response-1.0
|
||||
# MSIE 7 and newer should be able to use keepalive
|
||||
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,42 @@
|
||||
<VirtualHost *:80>
|
||||
ServerName encryption-example.demo
|
||||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot /var/www-encryption-example/static/
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
<Directory /var/www/>
|
||||
Options Indexes FollowSymLinks MultiViews
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
<Directory "/usr/lib/cgi-bin">
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
Alias /doc/ "/usr/share/doc/"
|
||||
<Directory "/usr/share/doc/">
|
||||
Options Indexes MultiViews FollowSymLinks
|
||||
AllowOverride None
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
Allow from 127.0.0.0/255.0.0.0 ::1/128
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
@@ -0,0 +1,42 @@
|
||||
<VirtualHost *:80>
|
||||
ServerName letsencrypt.demo
|
||||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot /var/www-letsencrypt-reworld/static/
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
<Directory /var/www/>
|
||||
Options Indexes FollowSymLinks MultiViews
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
<Directory "/usr/lib/cgi-bin">
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
Alias /doc/ "/usr/share/doc/"
|
||||
<Directory "/usr/share/doc/">
|
||||
Options Indexes MultiViews FollowSymLinks
|
||||
AllowOverride None
|
||||
Order deny,allow
|
||||
Deny from all
|
||||
Allow from 127.0.0.0/255.0.0.0 ::1/128
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
@@ -0,0 +1 @@
|
||||
../sites-available/000-default.conf
|
||||
@@ -0,0 +1 @@
|
||||
../sites-available/encryption-example.conf
|
||||
@@ -0,0 +1 @@
|
||||
../sites-available/letsencrypt.conf
|
||||
2
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/sites
vendored
Normal file
2
letsencrypt/client/tests/testdata/debian_apache_2_4/two_vhost_80/sites
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
sites-available/letsencrypt.conf, letencrypt.demo
|
||||
sites-available/encryption-example.conf, encryption-example.demo
|
||||
@@ -4,3 +4,4 @@ jsonschema==2.4.0
|
||||
python-augeas==0.5.0
|
||||
requests==2.4.3
|
||||
argparse==1.2.2
|
||||
mock==1.0.1
|
||||
|
||||
Reference in New Issue
Block a user