1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-18 00:02:25 +03:00

PEP8 support for acme, acme_test, apache_configurator

This commit is contained in:
James Kasten
2014-11-25 00:15:47 -08:00
parent 506c603e30
commit 8d1d9b0734
4 changed files with 258 additions and 158 deletions

View File

@@ -10,19 +10,18 @@ from letsencrypt.client import le_util
SCHEMATA = dict([
(schema, json.load(open(pkg_resources.resource_filename(
__name__, "schemata/%s.json" % schema)))) for schema in [
"authorization",
"authorizationRequest",
"certificate",
"certificateRequest",
"challenge",
"challengeRequest",
"defer",
"error",
"revocation",
"revocationRequest",
"statusRequest",
]
__name__, "schemata/%s.json" % schema))))
for schema in ["authorization",
"authorizationRequest",
"certificate",
"certificateRequest",
"challenge",
"challengeRequest",
"defer",
"error",
"revocation",
"revocationRequest",
"statusRequest"]
])

View File

@@ -10,10 +10,10 @@ class ACMEObjectValidateTest(unittest.TestCase):
def setUp(self):
self.schemata = {
'foo': {
'type' : 'object',
'properties' : {
'price' : {'type' : 'number'},
'name' : {'type' : 'string'},
'type': 'object',
'properties': {
'price': {'type': 'number'},
'name': {'type': 'string'},
},
},
}

View File

@@ -57,6 +57,7 @@ class VH(object):
def add_name(self, name):
self.names.append(name)
class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
State of Configurator:
@@ -137,16 +138,20 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
search = {}
path = {}
path["cert_file"] = self.find_directive(self.case_i("SSLCertificateFile"), None, vhost.path)
path["cert_key"] = self.find_directive(self.case_i("SSLCertificateKeyFile"), None, vhost.path)
path["cert_file"] = self.find_directive(case_i(
"SSLCertificateFile"), None, vhost.path)
path["cert_key"] = self.find_directive(case_i(
"SSLCertificateKeyFile"), None, vhost.path)
# Only include if a certificate chain is specified
if cert_chain is not None:
path["cert_chain"] = self.find_directive(self.case_i("SSLCertificateChainFile"), None, vhost.path)
path["cert_chain"] = self.find_directive(
case_i("SSLCertificateChainFile"), None, vhost.path)
if len(path["cert_file"]) == 0 or len(path["cert_key"]) == 0:
# Throw some "can't find all of the directives error"
logger.warn("Warn: cannot find a cert or key directive in " + vhost.path)
logger.warn(("Cannot find a cert or key directive in %s"
% vhost.path))
logger.warn("VirtualHost was not modified")
# Presumably break here so that the virtualhost is not modified
return False
@@ -161,7 +166,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
else:
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)
self.save_notes += ("Changed vhost at %s with addresses of %s\n" %
(vhost.file, vhost.addrs))
self.save_notes += "\tSSLCertificateFile %s\n" % cert
self.save_notes += "\tSSLCertificateKeyFile %s\n" % key
if cert_chain:
@@ -183,7 +189,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return vh
# Check for servernames/aliases for ssl hosts
for v in self.vhosts:
if v.ssl == True:
if v.ssl:
for n in v.names:
if n == name:
return v
@@ -197,12 +203,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Check for non ssl vhosts with servernames/aliases == 'name'
for v in self.vhosts:
if v.ssl == False:
if not v.ssl:
for n in v.names:
if n == name:
# When do we need to self.make_vhost_ssl(v)
return self.make_vhost_ssl(v)
#return v
# No matches, search for the default
for v in self.vhosts:
@@ -228,7 +233,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
all_names = set()
# Kept in same function to avoid multiple compilations of the regex
priv_ip_regex = "(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)"
priv_ip_regex = ("(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|"
"(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)")
privateIPs = re.compile(priv_ip_regex)
for v in self.vhosts:
@@ -246,32 +252,35 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return all_names
def __set_user_config_file(self, filename = ''):
def __set_user_config_file(self, filename=''):
if filename:
self.user_config_file = filename
else:
# Basic check to see if httpd.conf exists and is included via direct include
# Basic check to see if httpd.conf exists and
# in heirarchy via direct include
# httpd.conf was very common as a user file in Apache 2.2
if os.path.isfile(self.server_root + 'httpd.conf') and self.find_directive(self.case_i("Include"), self.case_i("httpd.conf")):
if (os.path.isfile(self.server_root + 'httpd.conf') and
self.find_directive(case_i("Include"),
case_i("httpd.conf"))):
self.user_config_file = self.server_root + 'httpd.conf'
else:
self.user_config_file = self.server_root + 'apache2.conf'
#def __is_private_ip(ipaddr):
# re.compile()
def __add_servernames(self, host):
"""
Helper function for get_virtual_hosts()
"""
nameMatch = self.aug.match("%s//*[self::directive=~regexp('%s')] | %s//*[self::directive=~regexp('%s')]" % (host.path, self.case_i('ServerName'), host.path, self.case_i('ServerAlias')))
nameMatch = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
"%s//*[self::directive=~regexp('%s')]" %
(host.path,
case_i('ServerName'),
host.path,
case_i('ServerAlias'))))
for name in nameMatch:
args = self.aug.match(name + "/*")
for arg in args:
host.add_name(self.aug.get(arg))
def __create_vhost(self, path):
"""
Private function used by get_virtual_hosts to create vhost objects
@@ -281,20 +290,26 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
for arg in args:
addrs.append(self.aug.get(arg))
is_ssl = False
if len(self.find_directive(self.case_i("SSLEngine"), self.case_i("on"), path)) > 0:
if len(self.find_directive(
case_i("SSLEngine"), case_i("on"), path)) > 0:
is_ssl = True
filename = self.get_file_path(path)
is_enabled = self.is_site_enabled(filename)
vhost = VH(filename, path, addrs, is_ssl, is_enabled)
self.__add_servernames(vhost)
return vhost
# TODO: make "sites-available" a configurable directory
def get_virtual_hosts(self):
"""
Returns list of virtual hosts found in the Apache configuration
"""
#Search sites-available, httpd.conf for possible virtual hosts
paths = self.aug.match("/files%ssites-available//*[label()=~regexp('%s')]" % (self.server_root, self.case_i('VirtualHost')))
# Search sites-available, httpd.conf for possible virtual hosts
paths = self.aug.match(
("/files%ssites-available//*[label()=~regexp('%s')]" %
(self.server_root, case_i('VirtualHost'))))
vhs = []
for p in paths:
vhs.append(self.__create_vhost(p))
@@ -309,7 +324,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# 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(self.case_i("NameVirtualHost"), None)
paths = self.find_directive(case_i("NameVirtualHost"), None)
name_vh = []
for p in paths:
name_vh.append(self.aug.get(p))
@@ -333,10 +348,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
aug_file_path = "/files%sports.conf" % self.server_root
self.add_dir_to_ifmodssl(aug_file_path, "NameVirtualHost", addr)
if len(self.find_directive(self.case_i("NameVirtualHost"), self.case_i(addr))) == 0:
# 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.add_dir_to_ifmodssl("/files" + self.server_root + "httpd.conf", "NameVirtualHost", addr)
self.add_dir_to_ifmodssl("/files%shttpd.conf" % self.server_root,
"NameVirtualHost",
addr)
self.save_notes += 'Setting %s to be NameBasedVirtualHost\n' % addr
@@ -368,10 +388,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# 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(self.case_i("Listen"), "443")) == 0:
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" + self.server_root + "ports.conf", "Listen", "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"
# Check for NameVirtualHost
@@ -380,14 +401,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
tup = addr.partition(":")
if tup[0] == "_default_":
if not self.is_name_vhost(default_addr):
logger.debug("Setting all VirtualHosts on " + default_addr + " to be name based virtual hosts")
logger.debug(("Setting all VirtualHosts on "
"%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):
logger.debug("Setting VirtualHost at" + addr + "to be a name based virtual host")
logger.debug(("Setting VirtualHost at %s "
"to be a name based virtual host" % addr))
self.add_name_vhost(addr)
return True
@@ -397,11 +420,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Returns the path to <IfMod mod>. Creates the block if it does
not exist
"""
ifMods = self.aug.match(aug_conf_path + "/IfModule/*[self::arg='" + mod + "']")
ifMods = self.aug.match(("%s/IfModule/*[self::arg='%s']" %
(aug_conf_path, mod)))
if len(ifMods) == 0:
self.aug.set("%s/IfModule[last() + 1]" % aug_conf_path, "")
self.aug.set("%s/IfModule[last()]/arg" % aug_conf_path, mod)
ifMods = self.aug.match("%s/IfModule/*[self::arg='%s']" % (aug_conf_path, mod))
ifMods = self.aug.match(("%s/IfModule/*[self::arg='%s']" %
(aug_conf_path, mod)))
# Strip off "arg" at end of first ifmod path
return ifMods[0][:len(ifMods[0]) - 3]
@@ -415,8 +440,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.aug.set(aug_conf_path + "/directive[last()]/arg", arg)
else:
for i in range(len(arg)):
self.aug.set(aug_conf_path + "/directive[last()]/arg["+str(i+1)+"]", arg[i])
self.aug.set("%s/directive[last()]/arg[%d]" %
(aug_conf_path, (i+1)),
arg[i])
def find_directive(self, directive, arg=None, start=""):
"""
@@ -436,51 +462,38 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if not start:
start = "/files%sapache2.conf" % self.server_root
#Debug code
#print "find_dir:", directive, "arg:", arg, " | Looking in:", start
# Debug code
# print "find_dir:", directive, "arg:", arg, " | Looking in:", start
# No regexp code
# if arg is None:
# matches = self.aug.match(start + "//*[self::directive='"+directive+"']/arg")
# matches = self.aug.match(start +
# "//*[self::directive='"+directive+"']/arg")
# else:
# matches = self.aug.match(start + "//*[self::directive='" + directive+"']/* [self::arg='" + arg + "']")
# matches = self.aug.match(start +
# "//*[self::directive='" + directive+"']/* [self::arg='" + arg + "']")
# includes = self.aug.match(start + "//* [self::directive='Include']/* [label()='arg']")
# includes = self.aug.match(start +
# "//* [self::directive='Include']/* [label()='arg']")
if arg is None:
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/arg" % directive)
ms = self.aug.match(("%s//*[self::directive=~regexp('%s')]/arg" %
(start, directive)))
else:
matches = self.aug.match(start + "//*[self::directive=~regexp('%s')]/*[self::arg=~regexp('%s')]" % (directive, arg))
ms = self.aug.match(("%s//*[self::directive=~regexp('%s')]/*"
"[self::arg=~regexp('%s')]" %
(start, directive, arg)))
includes = self.aug.match(start + "//* [self::directive=~regexp('%s')]/* [label()='arg']" % self.case_i('Include'))
includes = self.aug.match(("%s//* [self::directive=~regexp('%s')]/* "
"[label()='arg']" %
(start, case_i('Include'))))
for include in includes:
# start[6:] to strip off /files
matches.extend(self.find_directive(directive, arg, self.get_include_path(self.strip_dir(start[6:]), self.aug.get(include))))
ms.extend(self.find_directive(
directive, arg, self.get_include_path(strip_dir(start[6:]),
self.aug.get(include))))
return matches
def case_i(self, string):
"""
Returns a sloppy, but necessary version of a case insensitive regex.
Any string should be able to be submitted and the string is
escaped and then made case insensitive.
May be replaced by a more proper /i once augeas 1.0 is widely
supported.
"""
return "".join(["["+c.upper()+c.lower()+"]" if c.isalpha() else c for c in re.escape(string)])
def strip_dir(self, path):
"""
Precondition: file_path is a file path, ie. not an augeas section
or directive path
Returns the current directory from a file_path along with the file
"""
index = path.rfind("/")
if index > 0:
return path[:index+1]
# No directory
return ""
return ms
def get_include_path(self, cur_dir, arg):
"""
@@ -499,7 +512,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# check_config to validate apache config doesn't work because it
# would create a race condition between the check and this input
# TODO: Fix this
# TODO: Maybe... although I am convinced we have lost if
# Apache files can't be trusted. The augeas include path
# should be made to be exact.
# Check to make sure only expected characters are used <- maybe remove
# validChars = re.compile("[a-zA-Z0-9.*?_-/]*")
# matchObj = validChars.match(arg)
@@ -529,7 +545,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if "*" in split or "?" in split:
# Turn it into a augeas regex
# TODO: Can this instead be an augeas glob instead of regex
splitArg[idx] = "* [label()=~regexp('%s')]" % self.fnmatch_to_re(split)
splitArg[idx] = ("* [label()=~regexp('%s')]" %
self.fnmatch_to_re(split))
# Reassemble the argument
arg = "/".join(splitArg)
@@ -543,8 +560,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Checks apache2ctl to get loaded module list
"""
try:
#p = subprocess.check_output(['sudo', '/usr/sbin/apache2ctl', '-M'], stderr=open("/dev/null", 'w'))
p = subprocess.Popen(['sudo', '/usr/sbin/apache2ctl', '-M'], stdout=subprocess.PIPE, stderr=open("/dev/null", 'w')).communicate()[0]
# p=subprocess.check_output(['sudo', '/usr/sbin/apache2ctl', '-M'],
# stderr=open("/dev/null", 'w'))
p = subprocess.Popen(['sudo', '/usr/sbin/apache2ctl', '-M'],
stdout=subprocess.PIPE,
stderr=open(
"/dev/null", 'w')).communicate()[0]
except:
logger.error("Error accessing apache2ctl for loaded modules!")
logger.error("This may be caused by an Apache Configuration Error")
@@ -590,8 +611,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# change address to address:443, address:80
addr_match = "/files%s//* [label()=~regexp('%s')]/arg"
ssl_addr_p = self.aug.match(addr_match % (ssl_fp, self.case_i('VirtualHost')))
avail_addr_p = self.aug.match(addr_match % (avail_fp, self.case_i('VirtualHost')))
ssl_addr_p = self.aug.match(
addr_match % (ssl_fp, case_i('VirtualHost')))
avail_addr_p = self.aug.match(
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])
@@ -605,13 +629,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
ssl_addrs.append(ssl_new_addr)
# Add directives
vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" % (ssl_fp, self.case_i('VirtualHost')))
vh_p = self.aug.match(("/files%s//* [label()=~regexp('%s')]" %
(ssl_fp, case_i('VirtualHost'))))
if len(vh_p) != 1:
logger.error("Error: should only be one vhost in %s" % avail_fp)
sys.exit(1)
self.add_dir(vh_p[0], "SSLCertificateFile", "/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], "SSLCertificateFile",
"/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)
# Log actions and create save notes
@@ -630,7 +657,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# on after fully creating the new vhost
need_to_save = False
for i in range(len(nonssl_vhost.addrs)):
if self.is_name_vhost(nonssl_vhost.addrs[i]) and not self.is_name_vhost(ssl_addrs[i]):
if (self.is_name_vhost(nonssl_vhost.addrs[i]) and
not self.is_name_vhost(ssl_addrs[i])):
self.add_name_vhost(ssl_addrs[i])
logger.info("Enabling NameVirtualHosts on " + ssl_addrs[i])
need_to_save = True
@@ -640,7 +669,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return ssl_vhost
def enable_redirect(self, ssl_vhost):
"""
Adds Redirect directive to the port 80 equivalent of ssl_vhost
@@ -648,13 +676,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
ip addresses that serves on non-ssl ports
The function then adds the directive
"""
# TODO - Enable check to see if it is already there to avoid extra restart
# TODO: Enable check to see if it is already there
# to avoid the extra restart
self.enable_mod("rewrite")
general_v = self.__general_vhost(ssl_vhost)
if general_v is None:
#Add virtual_server with redirect
logger.debug("Did not find http version of ssl virtual host... creating")
# Add virtual_server with redirect
logger.debug(
"Did not find http version of ssl virtual host... creating")
return self.create_redirect_vhost(ssl_vhost)
else:
# Check if redirection already exists
@@ -666,10 +696,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
else:
logger.debug("Unknown redirect exists for this vhost")
return False, general_v
#Add directives to server
# Add directives to server
self.add_dir(general_v.path, "RewriteEngine", "On")
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)
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))
self.save()
return True, general_v
@@ -685,8 +717,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
-1 is also returned in case of no redirection/rewrite directives
"""
rewrite_path = self.find_directive(self.case_i("RewriteRule"), None, vhost.path)
redirect_path = self.find_directive(self.case_i("Redirect"), None, vhost.path)
rewrite_path = self.find_directive(
case_i("RewriteRule"), None, vhost.path)
redirect_path = self.find_directive(
case_i("Redirect"), None, vhost.path)
if redirect_path:
# "Existing Redirect directive for virtualhost"
@@ -736,16 +770,17 @@ LogLevel warn \n\
# Write out the file
# This is the default name
redirect_filename = "letsencrypt-redirect.conf"
redirect_filename = "le-redirect.conf"
# See if a more appropriate name can be applied
if len(ssl_vhost.names) > 0:
# Sanity check...
# make sure servername doesn't exceed filename length restriction
if ssl_vhost.names[0] < (255-23):
redirect_filename = "letsencrypt-redirect-" + ssl_vhost.names[0] + ".conf"
redirect_filename = "le-redirect-%s.conf" % ssl_vhost.names[0]
redirect_filepath = self.server_root + "sites-available/" + redirect_filename
redirect_filepath = ("%ssites-available/%s" %
(self.server_root, redirect_filename))
# Register the new file that will be created
# Note: always register the creation before writing to ensure file will
@@ -764,7 +799,9 @@ LogLevel warn \n\
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)
self.save_notes += ('Created a port 80 vhost, %s, for redirection to '
'ssl vhost %s\n' %
(new_vhost.file, ssl_vhost.file))
return True, new_vhost
@@ -827,12 +864,15 @@ LogLevel warn \n\
test_tup = test_a.partition(":")
if test_tup[0] == ssl_tup[0]:
# Check if found...
if test_tup[2] == "80" or test_tup[2] == "" or test_tup[2] == "*":
if (test_tup[2] == "80" or
test_tup[2] == "" or
test_tup[2] == "*"):
found += 1
break
# Check to make sure all addresses were found
# and names are equal
if found == len(ssl_vhost.addrs) and set(vh.names) == set(ssl_vhost.names):
if (found == len(ssl_vhost.addrs) and
set(vh.names) == set(ssl_vhost.names)):
return vh
return None
@@ -848,21 +888,24 @@ LogLevel warn \n\
Retrieve all certs and keys set in VirtualHosts on the Apache server
returns: list of tuples with form [(cert, key, path)]
"""
c_k = set()
c_k = set()
for vhost in self.vhosts:
if vhost.ssl:
cert_path = self.find_directive(self.case_i("SSLCertificateFile"), None, vhost.path)
key_path = self.find_directive(self.case_i("SSLCertificateKeyFile"), None, vhost.path)
cert_path = self.find_directive(
case_i("SSLCertificateFile"), None, vhost.path)
key_path = self.find_directive(
case_i("SSLCertificateKeyFile"), None, vhost.path)
# 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)
logger.error(("Too many cert or key directives in vhost "
"%s" % vhost.file))
sys.exit(40)
cert = os.path.abspath(self.aug.get(cert_path[0]))
key = os.path.abspath(self.aug.get(key_path[0]))
c_k.add( (cert, key, self.get_file_path(cert_path[0])) )
c_k.add((cert, key, self.get_file_path(cert_path[0])))
return c_k
@@ -877,7 +920,7 @@ LogLevel warn \n\
while True:
# Cast both to lowercase to be case insensitive
find_if = avail_fp.lower().find("/ifmodule")
if find_if != -1:
if find_if != -1:
avail_fp = avail_fp[:find_if]
continue
find_vh = avail_fp.lower().find("/virtualhost")
@@ -910,7 +953,8 @@ LogLevel warn \n\
return True
if "/sites-available/" in vhost.file:
enabled_path = "%ssites-enabled/%s" % (self.server_root, os.path.basename(vhost.file))
enabled_path = ("%ssites-enabled/%s" %
(self.server_root, os.path.basename(vhost.file)))
self.register_file_creation(False, enabled_path)
os.symlink(vhost.file, enabled_path)
vhost.enabled = True
@@ -925,9 +969,13 @@ LogLevel warn \n\
"""
try:
# Use check_output so the command will finish before reloading
subprocess.check_call(["sudo", "a2enmod", mod_name], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
subprocess.check_call(["sudo", "a2enmod", 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"], stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
subprocess.check_call(["sudo", "/etc/init.d/apache2", "restart"],
stdout=open("/dev/null", 'w'),
stderr=open("/dev/null", 'w'))
except Exception as e:
logger.error("Error enabling mod_" + mod_name)
logger.error("Exception: %s" % str(e))
@@ -958,19 +1006,21 @@ LogLevel warn \n\
"""
# Test if augeas included file for Httpd.lens
# Note: This works for augeas globs, ie. *.conf
incTest = self.aug.match("/augeas/load/Httpd/incl [. ='" + file_path + "']")
incTest = self.aug.match(
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
if not incTest:
# Load up files
#self.httpd_incl.append(file_path)
#self.aug.add_transform("Httpd.lns", self.httpd_incl, None, self.httpd_excl)
# self.httpd_incl.append(file_path)
# self.aug.add_transform("Httpd.lns",
# self.httpd_incl, None, self.httpd_excl)
self.__add_httpd_transform(file_path)
self.aug.load()
def save_apache_config(self):
# Not currently used
# Should be safe because it is a protected directory
shutil.copytree(self.server_root, CONFIG.BACKUP_DIR + "apache2-" + str(time.time()))
shutil.copytree(self.server_root,
"%sapache2-%s" % (CONFIG.BACKUP_DIR, str(time.time())))
def verify_setup(self):
'''
@@ -996,7 +1046,15 @@ LogLevel warn \n\
# I had no luck
# This is a hack... work around... submit to augeas if still not fixed
excl = ["*.augnew", "*.augsave", "*.dpkg-dist", "*.dpkg-bak", "*.dpkg-new", "*.dpkg-old", "*.rpmsave", "*.rpmnew", "*~", self.server_root + "*.augsave", self.server_root + "*~", self.server_root + "*/*augsave", self.server_root + "*/*~", self.server_root + "*/*/*.augsave", self.server_root + "*/*/*~"]
excl = ["*.augnew", "*.augsave", "*.dpkg-dist", "*.dpkg-bak",
"*.dpkg-new", "*.dpkg-old", "*.rpmsave", "*.rpmnew",
"*~",
self.server_root + "*.augsave",
self.server_root + "*~",
self.server_root + "*/*augsave",
self.server_root + "*/*~",
self.server_root + "*/*/*.augsave",
self.server_root + "*/*/*~"]
for i in range(len(excl)):
self.aug.set("/augeas/load/Httpd/excl[%d]" % (i+1), excl[i])
@@ -1007,12 +1065,13 @@ LogLevel warn \n\
"""
Restarts apache server
"""
#TODO: This should be written to use the process returncode
# TODO: This should be written to use the process returncode
try:
p = subprocess.Popen(['/etc/init.d/apache2', 'restart'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.Popen(['/etc/init.d/apache2', 'restart'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
text = p.communicate()
if p.returncode != 0:
# Enter recovery routine...
logger.error("Configtest failed")
@@ -1021,7 +1080,8 @@ LogLevel warn \n\
return False
except:
logger.fatal("Apache Restart Failed - Please Check the Configuration")
logger.fatal(("Apache Restart Failed - "
"Please Check the Configuration"))
sys.exit(1)
return True
@@ -1037,7 +1097,10 @@ LogLevel warn \n\
def config_test(self):
try:
p = subprocess.Popen(['sudo', '/usr/sbin/apache2ctl', 'configtest'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.Popen(
['sudo', '/usr/sbin/apache2ctl', 'configtest'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
text = p.communicate()
except:
logger.fatal("Unable to run /usr/sbin/apache2ctl configtest")
@@ -1085,7 +1148,8 @@ LogLevel warn \n\
for tup in chall_dict["listSNITuple"]:
vhost = self.choose_virtual_host(tup[0])
if vhost is None:
logger.error("No vhost exists with servername or alias of:%s" % tup[0])
logger.error(("No vhost exists with servername "
"or alias of: %s" % tup[0]))
logger.error("No _default_:443 vhost exists")
logger.error("Please specify servernames in the Apache config")
return None
@@ -1108,22 +1172,24 @@ LogLevel warn \n\
# Need to decode from base64
r = le_util.jose_b64decode(t[1])
ext = self.dvsni_gen_ext(r, s)
self.dvsni_create_chall_cert(t[0], ext, t[2], chall_dict["dvsni_key"])
self.dvsni_create_chall_cert(
t[0], ext, t[2], chall_dict["dvsni_key"])
self.dvsni_mod_config(self.user_config_file, chall_dict["listSNITuple"],
chall_dict["dvsni_key"], addresses)
self.dvsni_mod_config(self.user_config_file,
chall_dict["listSNITuple"],
chall_dict["dvsni_key"],
addresses)
# Save reversible changes and restart the server
self.save("SNI Challenge", True)
self.restart(True)
s = le_util.jose_b64encode(s)
return {"type":"dvsni", "s":s}
return {"type": "dvsni", "s": s}
def cleanup(self):
self.revert_challenge_config()
self.restart(True)
def dvsni_get_cert_file(self, nonce):
"""
Returns standardized name for challenge certificate
@@ -1163,12 +1229,15 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
"""
Modifies Apache config files to include the challenge virtual servers
mainConfig: string - file path to Apache user config file
param mainConfig: file path to Apache user config file
type mainConfig: string
listSNITuple: list of tuples with form (addr, y, nonce, ext_oid)
addr (string), y (byte array), nonce (hex string), ext_oid (string)
addr (string), y (byte array), nonce (hex string),
ext_oid (string)
key: string - file path to key
result: Apache config includes virtual servers for issued challenges
result: Apache config includes virtual servers for issued challs
"""
# Check to make sure options-ssl.conf is installed
@@ -1180,7 +1249,9 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
# TODO: Use ip address of existing vhost instead of relying on FQDN
configText = "<IfModule mod_ssl.c> \n"
for idx, lis in enumerate(listlistAddrs):
configText += self.__getConfigText(listSNITuple[idx][2], lis, dvsni_key)
configText += self.__getConfigText(listSNITuple[idx][2],
lis,
dvsni_key)
configText += "</IfModule> \n"
self.dvsni_conf_include_check(mainConfig)
@@ -1189,8 +1260,6 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
newConf.write(configText)
newConf.close()
def dvsni_conf_include_check(self, mainConfig):
"""
Adds DVSNI challenge include file if it does not already exist
@@ -1198,15 +1267,17 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
mainConfig: string - file path to main user apache config file
result: User Apache configuration includes chocolate sni challenge file
result: User Apache configuration includes chocolate sni challenge file
"""
if len(self.find_directive(self.case_i("Include"), CONFIG.APACHE_CHALLENGE_CONF)) == 0:
#print "Including challenge virtual host(s)"
self.add_dir("/files" + mainConfig, "Include", CONFIG.APACHE_CHALLENGE_CONF)
if len(self.find_directive(
case_i("Include"), CONFIG.APACHE_CHALLENGE_CONF)) == 0:
# print "Including challenge virtual host(s)"
self.add_dir("/files" + mainConfig,
"Include", CONFIG.APACHE_CHALLENGE_CONF)
def dvsni_create_chall_cert(self, name, ext, nonce, key):
"""
Modifies challenge certificate configuration and calls openssl binary to create a certificate
Modifies challenge certificate configuration and creates challenge cert
ext: string - hex z value
nonce: string - hex
@@ -1216,7 +1287,10 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
"""
self.register_file_creation(True, self.dvsni_get_cert_file(nonce))
cert_pem = crypto_util.make_ss_cert(key, [nonce + CONFIG.INVALID_EXT, name, ext])
cert_pem = crypto_util.make_ss_cert(
key, [nonce + CONFIG.INVALID_EXT, name, ext])
with open(self.dvsni_get_cert_file(nonce), 'w') as f:
f.write(cert_pem)
@@ -1235,6 +1309,33 @@ DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
return h.hexdigest() + CONFIG.INVALID_EXT
def case_i(string):
"""
Returns a sloppy, but necessary version of a case insensitive regex.
Any string should be able to be submitted and the string is
escaped and then made case insensitive.
May be replaced by a more proper /i once augeas 1.0 is widely
supported.
"""
return "".join(["["+c.upper()+c.lower()+"]"
if c.isalpha() else c for c in re.escape(string)])
def strip_dir(path):
"""
Precondition: file_path is a file path, ie. not an augeas section
or directive path
Returns the current directory from a file_path along with the file
"""
index = path.rfind("/")
if index > 0:
return path[:index+1]
# No directory
return ""
def main():
config = ApacheConfigurator()
logger.setLogger(logger.FileLogger(sys.stdout))
@@ -1246,7 +1347,8 @@ def main():
for name in v.names:
print name
"""
print config.find_directive(config.case_i("NameVirtualHost"), config.case_i("holla:443"))
print config.find_directive(
config.case_i("NameVirtualHost"), config.case_i("holla:443"))
"""
for m in config.find_directive("Listen", "443"):
@@ -1262,18 +1364,18 @@ def main():
test_file = "/home/james/Desktop/ports_test.conf"
config.parse_file(test_file)
config.aug.insert("/files" + test_file + "/IfModule[1]/arg", "directive", False)
config.aug.set("/files" + test_file + "/IfModule[1]/directive[1]", "Listen")
config.aug.set("/files" + test_file + "/IfModule[1]/directive[1]/arg", "556")
config.aug.set("/files" + test_file + "/IfModule[1]/directive[2]", "Listen")
config.aug.set("/files" + test_file + "/IfModule[1]/directive[2]/arg", "555")
config.aug.insert("/files"+test_file+"/IfModule[1]/arg","directive",False)
config.aug.set("/files" +test_file+ "/IfModule[1]/directive[1]", "Listen")
config.aug.set("/files" +test_file+ "/IfModule[1]/directive[1]/arg", "556")
config.aug.set("/files" +test_file+ "/IfModule[1]/directive[2]", "Listen")
config.aug.set("/files" +test_file+ "/IfModule[1]/directive[2]/arg", "555")
#config.save_notes = "Added listen 431 for test"
#config.register_file_creation("/home/james/Desktop/new_file.txt")
#config.save("Testing Saves", False)
#config.recover_checkpoint(1)
"""
#config.display_checkpoints()
# config.display_checkpoints()
config.config_test()
"""
# Testing redirection and make_vhost_ssl
@@ -1291,8 +1393,11 @@ def main():
"""
for vh in config.vhosts:
if len(vh.names) > 0:
config.deploy_cert(vh, "/home/james/Documents/apache_choc/req.pem", "/home/james/Documents/apache_choc/key.pem", "/home/james/Downloads/sub.class1.server.ca.pem")
"""
config.deploy_cert(vh,
"/home/james/Documents/apache_choc/req.pem",
"/home/james/Documents/apache_choc/key.pem",
"/home/james/Downloads/sub.class1.server.ca.pem")
"""
if __name__ == "__main__":
main()

View File

@@ -82,10 +82,6 @@ class Client(object):
else:
sys.exit(0)
# Display choice of CA screen
# TODO: Use correct server depending on CA
#choice = self.choice_of_ca()
# Request Challenges
challenge_msg = self.acme_challenge()