Merge remote-tracking branch 'origin/master' into dialog-escape

This commit is contained in:
Peter Eckersley 2016-06-22 15:35:07 -07:00
commit e231dae2c1
493 changed files with 8408 additions and 4800 deletions

3
.coveragerc Normal file
View file

@ -0,0 +1,3 @@
[report]
# show lines missing coverage in output
show_missing = True

11
.gitattributes vendored
View file

@ -1,7 +1,16 @@
* text=auto eol=lf
#Default, normalize CRLF into LF in non-binary files
# Files identified as binary by Git are not changed
* crlf=auto
# special files
*.sh crlf=input
*.py crlf=input
*.bat text eol=crlf
*.der binary
*.gz binary
*.jpeg binary
*.jpg binary
*.png binary
*.gz binary

1
.gitignore vendored
View file

@ -8,6 +8,7 @@ dist*/
/.tox/
/releases/
letsencrypt.log
certbot.log
letsencrypt-auto-source/letsencrypt-auto.sig.lzma.base64
# coverage

View file

@ -4,39 +4,48 @@ cache:
directories:
- $HOME/.cache/pip
services:
- rabbitmq
- mariadb
# apacheconftest
#- apache2
# This makes sure we get a host with docker-compose present.
dist: trusty
# http://docs.travis-ci.com/user/ci-environment/#CI-environment-OS
# gimme has to be kept in sync with Boulder's Go version setting in .travis.yml
before_install:
- 'dpkg -s libaugeas0'
- '[ "xxx$BOULDER_INTEGRATION" = "xxx" ] || eval "$(gimme 1.5.1)"'
# using separate envs with different TOXENVs creates 4x1 Travis build
# matrix, which allows us to clearly distinguish which component under
# test has failed
env:
global:
- GOPATH=/tmp/go
- PATH=$GOPATH/bin:$PATH
- BOULDERPATH=$PWD/boulder/
matrix:
include:
- python: "2.6"
env: TOXENV=py26 BOULDER_INTEGRATION=1
sudo: true
after_failure:
- sudo cat /var/log/mysql/error.log
- ps aux | grep mysql
- python: "2.6"
env: TOXENV=py26-oldest BOULDER_INTEGRATION=1
sudo: true
after_failure:
- sudo cat /var/log/mysql/error.log
- ps aux | grep mysql
- python: "2.7"
env: TOXENV=apacheconftest
sudo: required
- python: "2.7"
env: TOXENV=py27 BOULDER_INTEGRATION=1
sudo: true
after_failure:
- sudo cat /var/log/mysql/error.log
- ps aux | grep mysql
- python: "2.7"
env: TOXENV=py27-oldest BOULDER_INTEGRATION=1
sudo: true
after_failure:
- sudo cat /var/log/mysql/error.log
- ps aux | grep mysql
- python: "2.7"
env: TOXENV=lint
- sudo: required
@ -66,16 +75,16 @@ sudo: false
addons:
# Custom /etc/hosts required for simple verification of http-01
# and tls-sni-01, and for letsencrypt_test_nginx
# and tls-sni-01, and for certbot_test_nginx
hosts:
- le.wtf
- le1.wtf
- le2.wtf
- le3.wtf
- nginx.wtf
- boulder
- boulder-mysql
- boulder-rabbitmq
mariadb: "10.0"
apt:
sources:
- augeas
@ -88,17 +97,14 @@ addons:
- libssl-dev
- libffi-dev
- ca-certificates
# For letsencrypt-nginx integration testing
# For certbot-nginx integration testing
- nginx-light
- openssl
# For Boulder integration testing
- rsyslog
# for apacheconftest
#- realpath
#- apache2
#- libapache2-mod-wsgi
#- libapache2-mod-macro
#- sudo
- apache2
- libapache2-mod-wsgi
- libapache2-mod-macro
- sudo
install: "travis_retry pip install tox coveralls"
script: 'travis_retry tox && ([ "xxx$BOULDER_INTEGRATION" = "xxx" ] || ./tests/travis-integration.sh)'

View file

@ -3,9 +3,9 @@ ChangeLog
Please note:
the change log will only get updated after first release - for now please use the
`commit log <https://github.com/letsencrypt/letsencrypt/commits/master>`_.
`commit log <https://github.com/certbot/certbot/commits/master>`_.
To see the changes in a given release, inspect the github milestone for the
release. For instance:
https://github.com/letsencrypt/letsencrypt/issues?utf8=%E2%9C%93&q=milestone%3A0.3.0
https://github.com/certbot/certbot/issues?utf8=%E2%9C%93&q=milestone%3A0.3.0

View file

@ -15,4 +15,4 @@ to the Sphinx generated docs is provided below.
-->
https://letsencrypt.readthedocs.org/en/latest/contributing.html
https://certbot.eff.org/docs/contributing.html

View file

@ -10,20 +10,21 @@ MAINTAINER William Budington <bill@eff.org>
EXPOSE 443
# TODO: make sure --config-dir and --work-dir cannot be changed
# through the CLI (letsencrypt-docker wrapper that uses standalone
# through the CLI (certbot-docker wrapper that uses standalone
# authenticator and text mode only?)
VOLUME /etc/letsencrypt /var/lib/letsencrypt
WORKDIR /opt/letsencrypt
WORKDIR /opt/certbot
# no need to mkdir anything:
# https://docs.docker.com/reference/builder/#copy
# If <dest> doesn't exist, it is created along with all missing
# directories in its path.
ENV DEBIAN_FRONTEND=noninteractive
COPY letsencrypt-auto-source/letsencrypt-auto /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto
RUN /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \
COPY letsencrypt-auto-source/letsencrypt-auto /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto
RUN /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* \
/tmp/* \
@ -33,7 +34,7 @@ RUN /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-
# Dockerfile we make sure we cache as much as possible
COPY setup.py README.rst CHANGES.rst MANIFEST.in letsencrypt-auto-source/pieces/pipstrap.py /opt/letsencrypt/src/
COPY setup.py README.rst CHANGES.rst MANIFEST.in letsencrypt-auto-source/pieces/pipstrap.py /opt/certbot/src/
# all above files are necessary for setup.py and venv setup, however,
# package source code directory has to be copied separately to a
@ -44,26 +45,26 @@ COPY setup.py README.rst CHANGES.rst MANIFEST.in letsencrypt-auto-source/pieces/
# copied, just its contents." Order again matters, three files are far
# more likely to be cached than the whole project directory
COPY letsencrypt /opt/letsencrypt/src/letsencrypt/
COPY acme /opt/letsencrypt/src/acme/
COPY letsencrypt-apache /opt/letsencrypt/src/letsencrypt-apache/
COPY letsencrypt-nginx /opt/letsencrypt/src/letsencrypt-nginx/
COPY certbot /opt/certbot/src/certbot/
COPY acme /opt/certbot/src/acme/
COPY certbot-apache /opt/certbot/src/certbot-apache/
COPY certbot-nginx /opt/certbot/src/certbot-nginx/
RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv
RUN virtualenv --no-site-packages -p python2 /opt/certbot/venv
# PATH is set now so pipstrap upgrades the correct (v)env
ENV PATH /opt/letsencrypt/venv/bin:$PATH
RUN /opt/letsencrypt/venv/bin/python /opt/letsencrypt/src/pipstrap.py && \
/opt/letsencrypt/venv/bin/pip install \
-e /opt/letsencrypt/src/acme \
-e /opt/letsencrypt/src \
-e /opt/letsencrypt/src/letsencrypt-apache \
-e /opt/letsencrypt/src/letsencrypt-nginx
ENV PATH /opt/certbot/venv/bin:$PATH
RUN /opt/certbot/venv/bin/python /opt/certbot/src/pipstrap.py && \
/opt/certbot/venv/bin/pip install \
-e /opt/certbot/src/acme \
-e /opt/certbot/src \
-e /opt/certbot/src/certbot-apache \
-e /opt/certbot/src/certbot-nginx
# install in editable mode (-e) to save space: it's not possible to
# "rm -rf /opt/letsencrypt/src" (it's stays in the underlaying image);
# "rm -rf /opt/certbot/src" (it's stays in the underlaying image);
# this might also help in debugging: you can "docker run --entrypoint
# bash" and investigate, apply patches, etc.
ENTRYPOINT [ "letsencrypt" ]
ENTRYPOINT [ "certbot" ]

View file

@ -9,11 +9,11 @@ MAINTAINER Yan <yan@eff.org>
EXPOSE 443
# TODO: make sure --config-dir and --work-dir cannot be changed
# through the CLI (letsencrypt-docker wrapper that uses standalone
# through the CLI (certbot-docker wrapper that uses standalone
# authenticator and text mode only?)
VOLUME /etc/letsencrypt /var/lib/letsencrypt
WORKDIR /opt/letsencrypt
WORKDIR /opt/certbot
# no need to mkdir anything:
# https://docs.docker.com/reference/builder/#copy
@ -22,8 +22,8 @@ WORKDIR /opt/letsencrypt
# TODO: Install non-default Python versions for tox.
# TODO: Install Apache/Nginx for plugin development.
COPY letsencrypt-auto-source/letsencrypt-auto /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto
RUN /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \
COPY letsencrypt-auto-source/letsencrypt-auto /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto
RUN /opt/certbot/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-only && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* \
/tmp/* \
@ -32,7 +32,7 @@ RUN /opt/letsencrypt/src/letsencrypt-auto-source/letsencrypt-auto --os-packages-
# the above is not likely to change, so by putting it further up the
# Dockerfile we make sure we cache as much as possible
COPY setup.py README.rst CHANGES.rst MANIFEST.in linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/
COPY setup.py README.rst CHANGES.rst MANIFEST.in linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/certbot/src/
# all above files are necessary for setup.py, however, package source
# code directory has to be copied separately to a subdirectory...
@ -42,27 +42,27 @@ COPY setup.py README.rst CHANGES.rst MANIFEST.in linter_plugin.py tox.cover.sh t
# copied, just its contents." Order again matters, three files are far
# more likely to be cached than the whole project directory
COPY letsencrypt /opt/letsencrypt/src/letsencrypt/
COPY acme /opt/letsencrypt/src/acme/
COPY letsencrypt-apache /opt/letsencrypt/src/letsencrypt-apache/
COPY letsencrypt-nginx /opt/letsencrypt/src/letsencrypt-nginx/
COPY letshelp-letsencrypt /opt/letsencrypt/src/letshelp-letsencrypt/
COPY letsencrypt-compatibility-test /opt/letsencrypt/src/letsencrypt-compatibility-test/
COPY tests /opt/letsencrypt/src/tests/
COPY certbot /opt/certbot/src/certbot/
COPY acme /opt/certbot/src/acme/
COPY certbot-apache /opt/certbot/src/certbot-apache/
COPY certbot-nginx /opt/certbot/src/certbot-nginx/
COPY letshelp-certbot /opt/certbot/src/letshelp-certbot/
COPY certbot-compatibility-test /opt/certbot/src/certbot-compatibility-test/
COPY tests /opt/certbot/src/tests/
RUN virtualenv --no-site-packages -p python2 /opt/letsencrypt/venv && \
/opt/letsencrypt/venv/bin/pip install \
-e /opt/letsencrypt/src/acme \
-e /opt/letsencrypt/src \
-e /opt/letsencrypt/src/letsencrypt-apache \
-e /opt/letsencrypt/src/letsencrypt-nginx \
-e /opt/letsencrypt/src/letshelp-letsencrypt \
-e /opt/letsencrypt/src/letsencrypt-compatibility-test \
-e /opt/letsencrypt/src[dev,docs]
RUN virtualenv --no-site-packages -p python2 /opt/certbot/venv && \
/opt/certbot/venv/bin/pip install \
-e /opt/certbot/src/acme \
-e /opt/certbot/src \
-e /opt/certbot/src/certbot-apache \
-e /opt/certbot/src/certbot-nginx \
-e /opt/certbot/src/letshelp-certbot \
-e /opt/certbot/src/certbot-compatibility-test \
-e /opt/certbot/src[dev,docs]
# install in editable mode (-e) to save space: it's not possible to
# "rm -rf /opt/letsencrypt/src" (it's stays in the underlaying image);
# "rm -rf /opt/certbot/src" (it's stays in the underlaying image);
# this might also help in debugging: you can "docker run --entrypoint
# bash" and investigate, apply patches, etc.
ENV PATH /opt/letsencrypt/venv/bin:$PATH
ENV PATH /opt/certbot/venv/bin:$PATH

View file

@ -1,4 +1,4 @@
Let's Encrypt Python Client
Certbot ACME Client
Copyright (c) Electronic Frontier Foundation and others
Licensed Apache Version 2.0

View file

@ -5,4 +5,4 @@ include LICENSE.txt
include linter_plugin.py
recursive-include docs *
recursive-include examples *
recursive-include letsencrypt/tests/testdata *
recursive-include certbot/tests/testdata *

View file

@ -3,51 +3,71 @@
Disclaimer
==========
The Let's Encrypt Client is **BETA SOFTWARE**. It contains plenty of bugs and
rough edges, and should be tested thoroughly in staging environments before use
on production systems.
Certbot (previously, the Let's Encrypt client) is **BETA SOFTWARE**. It
contains plenty of bugs and rough edges, and should be tested thoroughly in
staging environments before use on production systems.
For more information regarding the status of the project, please see
https://letsencrypt.org. Be sure to checkout the
`Frequently Asked Questions (FAQ) <https://community.letsencrypt.org/t/frequently-asked-questions-faq/26#topic-title>`_.
About the Let's Encrypt Client
About Certbot
==============================
The Let's Encrypt Client is a fully-featured, extensible client for the Let's
Certbot is a fully-featured, extensible client for the Let's
Encrypt CA (or any other CA that speaks the `ACME
<https://github.com/ietf-wg-acme/acme/blob/master/draft-ietf-acme-acme.md>`_
protocol) that can automate the tasks of obtaining certificates and
configuring webservers to use them. This client runs on Unix-based operating
systems.
Until May 2016, Certbot was named simply ``letsencrypt`` or ``letsencrypt-auto``,
depending on install method. Instructions on the Internet, and some pieces of the
software, may still refer to this older name.
Contributing
------------
If you'd like to contribute to this project please read `Developer Guide
<https://certbot.eff.org/docs/contributing.html>`_.
.. _installation:
Installation
------------
If ``letsencrypt`` is packaged for your Unix OS, you can install it from
there, and run it by typing ``letsencrypt``. Because not all operating
systems have packages yet, we provide a temporary solution via the
``letsencrypt-auto`` wrapper script, which obtains some dependencies
from your OS and puts others in a python virtual environment::
If ``certbot`` (or ``letsencrypt``) is packaged for your Unix OS (visit
certbot.eff.org_ to find out), you can install it
from there, and run it by typing ``certbot`` (or ``letsencrypt``). Because
not all operating systems have packages yet, we provide a temporary solution
via the ``certbot-auto`` wrapper script, which obtains some dependencies from
your OS and puts others in a python virtual environment::
user@webserver:~$ git clone https://github.com/letsencrypt/letsencrypt
user@webserver:~$ cd letsencrypt
user@webserver:~/letsencrypt$ ./letsencrypt-auto --help
user@webserver:~$ wget https://dl.eff.org/certbot-auto
user@webserver:~$ chmod a+x ./certbot-auto
user@webserver:~$ ./certbot-auto --help
Or for full command line help, type::
.. hint:: The certbot-auto download is protected by HTTPS, which is pretty good, but if you'd like to
double check the integrity of the ``certbot-auto`` script, you can use these steps for verification before running it::
./letsencrypt-auto --help all
user@server:~$ wget -N https://dl.eff.org/certbot-auto.asc
user@server:~$ gpg2 --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
user@server:~$ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto
``letsencrypt-auto`` updates to the latest client release automatically. And
since ``letsencrypt-auto`` is a wrapper to ``letsencrypt``, it accepts exactly
And for full command line help, you can type::
./certbot-auto --help all
``certbot-auto`` updates to the latest client release automatically. And
since ``certbot-auto`` is a wrapper to ``certbot``, it accepts exactly
the same command line flags and arguments. More details about this script and
other installation methods can be found `in the User Guide
<https://letsencrypt.readthedocs.org/en/latest/using.html#installation>`_.
<https://certbot.eff.org/docs/using.html#installation>`_.
How to run the client
---------------------
In many cases, you can just run ``letsencrypt-auto`` or ``letsencrypt``, and the
In many cases, you can just run ``certbot-auto`` or ``certbot``, and the
client will guide you through the process of obtaining and installing certs
interactively.
@ -56,7 +76,7 @@ For instance, if you want to obtain a cert for ``example.com``,
``www.example.com``, and ``other.example.net``, using the Apache plugin to both
obtain and install the certs, you could do this::
./letsencrypt-auto --apache -d example.com -d www.example.com -d other.example.net
./certbot-auto --apache -d example.com -d www.example.com -d other.example.net
(The first time you run the command, it will make an account, and ask for an
email and agreement to the Let's Encrypt Subscriber Agreement; you can
@ -65,7 +85,7 @@ automate those with ``--email`` and ``--agree-tos``)
If you want to use a webserver that doesn't have full plugin support yet, you
can still use "standalone" or "webroot" plugins to obtain a certificate::
./letsencrypt-auto certonly --standalone --email admin@example.com -d example.com -d www.example.com -d other.example.net
./certbot-auto certonly --standalone --email admin@example.com -d example.com -d www.example.com -d other.example.net
Understanding the client in more depth
@ -73,21 +93,21 @@ Understanding the client in more depth
To understand what the client is doing in detail, it's important to
understand the way it uses plugins. Please see the `explanation of
plugins <https://letsencrypt.readthedocs.org/en/latest/using.html#plugins>`_ in
plugins <https://certbot.eff.org/docs/using.html#plugins>`_ in
the User Guide.
Links
=====
Documentation: https://letsencrypt.readthedocs.org
Documentation: https://certbot.eff.org/docs
Software project: https://github.com/letsencrypt/letsencrypt
Software project: https://github.com/certbot/certbot
Notes for developers: https://letsencrypt.readthedocs.org/en/latest/contributing.html
Notes for developers: https://certbot.eff.org/docs/contributing.html
Main Website: https://letsencrypt.org/
IRC Channel: #letsencrypt on `Freenode`_
IRC Channel: #letsencrypt on `Freenode`_ or #certbot on `OFTC`_
Community: https://community.letsencrypt.org
@ -103,12 +123,12 @@ email to client-dev+subscribe@letsencrypt.org)
.. |build-status| image:: https://travis-ci.org/letsencrypt/letsencrypt.svg?branch=master
:target: https://travis-ci.org/letsencrypt/letsencrypt
.. |build-status| image:: https://travis-ci.org/certbot/certbot.svg?branch=master
:target: https://travis-ci.org/certbot/certbot
:alt: Travis CI status
.. |coverage| image:: https://coveralls.io/repos/letsencrypt/letsencrypt/badge.svg?branch=master
:target: https://coveralls.io/r/letsencrypt/letsencrypt
.. |coverage| image:: https://coveralls.io/repos/certbot/certbot/badge.svg?branch=master
:target: https://coveralls.io/r/certbot/certbot
:alt: Coverage status
.. |docs| image:: https://readthedocs.org/projects/letsencrypt/badge/
@ -128,16 +148,15 @@ System Requirements
===================
The Let's Encrypt Client presently only runs on Unix-ish OSes that include
Python 2.6 or 2.7; Python 3.x support will be added after the Public Beta
launch. The client requires root access in order to write to
``/etc/letsencrypt``, ``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to
bind to ports 80 and 443 (if you use the ``standalone`` plugin) and to read and
modify webserver configurations (if you use the ``apache`` or ``nginx``
plugins). If none of these apply to you, it is theoretically possible to run
without root privileges, but for most users who want to avoid running an ACME
client as root, either `letsencrypt-nosudo
<https://github.com/diafygi/letsencrypt-nosudo>`_ or `simp_le
<https://github.com/kuba/simp_le>`_ are more appropriate choices.
Python 2.6 or 2.7; Python 3.x support will hopefully be added in the future. The
client requires root access in order to write to ``/etc/letsencrypt``,
``/var/log/letsencrypt``, ``/var/lib/letsencrypt``; to bind to ports 80 and 443
(if you use the ``standalone`` plugin) and to read and modify webserver
configurations (if you use the ``apache`` or ``nginx`` plugins). If none of
these apply to you, it is theoretically possible to run without root privileges,
but for most users who want to avoid running an ACME client as root, either
`letsencrypt-nosudo <https://github.com/diafygi/letsencrypt-nosudo>`_ or
`simp_le <https://github.com/kuba/simp_le>`_ are more appropriate choices.
The Apache plugin currently requires a Debian-based OS with augeas version
1.0; this includes Ubuntu 12.04+ and Debian 7+.
@ -152,10 +171,10 @@ Current Features
- standalone (runs its own simple webserver to prove you control a domain)
- webroot (adds files to webroot directories in order to prove control of
domains and obtain certs)
- nginx/0.8.48+ (highly experimental, not included in letsencrypt-auto)
- nginx/0.8.48+ (highly experimental, not included in certbot-auto)
* The private key is generated locally on your system.
* Can talk to the Let's Encrypt CA or optionally to other ACME
* Can talk to the Let's Encrypt CA or optionally to other ACME
compliant services.
* Can get domain-validated (DV) certificates.
* Can revoke certificates.
@ -170,4 +189,6 @@ Current Features
.. _Freenode: https://webchat.freenode.net?channels=%23letsencrypt
.. _OFTC: https://webchat.oftc.net?channels=%23certbot
.. _client-dev: https://groups.google.com/a/letsencrypt.org/forum/#!forum/client-dev
.. _certbot.eff.org: https://certbot.eff.org/

View file

@ -21,12 +21,6 @@ persistent=yes
# usually to register additional checkers.
load-plugins=linter_plugin
# DEPRECATED
include-ids=no
# DEPRECATED
symbols=no
# Use multiple processes to speed up Pylint.
jobs=1

View file

@ -500,7 +500,7 @@ class DNS(_TokenChallenge):
"""
return DNSResponse(validation=self.gen_validation(
self, account_key, **kwargs))
account_key, **kwargs))
def validation_domain_name(self, name):
"""Domain name for TXT validation record.

View file

@ -512,6 +512,10 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
self.verify_ssl = verify_ssl
self._nonces = set()
self.user_agent = user_agent
self.session = requests.Session()
def __del__(self):
self.session.close()
def _wrap_in_jws(self, obj, nonce):
"""Wrap `JSONDeSerializable` object in JWS.
@ -606,7 +610,7 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
kwargs['verify'] = self.verify_ssl
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('User-Agent', self.user_agent)
response = requests.request(method, url, *args, **kwargs)
response = self.session.request(method, url, *args, **kwargs)
logging.debug('Received %s. Headers: %s. Content: %r',
response, response.headers, response.content)
return response

View file

@ -484,9 +484,11 @@ class ClientNetworkTest(unittest.TestCase):
def test_check_response_not_ok_jobj_no_error(self):
self.response.ok = False
self.response.json.return_value = {}
# pylint: disable=protected-access
self.assertRaises(
errors.ClientError, self.net._check_response, self.response)
with mock.patch('acme.client.messages.Error.from_json') as from_json:
from_json.side_effect = jose.DeserializationError
# pylint: disable=protected-access
self.assertRaises(
errors.ClientError, self.net._check_response, self.response)
def test_check_response_not_ok_jobj_error(self):
self.response.ok = False
@ -528,40 +530,49 @@ class ClientNetworkTest(unittest.TestCase):
self.assertEqual(
self.response, self.net._check_response(self.response))
@mock.patch('acme.client.requests')
def test_send_request(self, mock_requests):
mock_requests.request.return_value = self.response
def test_send_request(self):
self.net.session = mock.MagicMock()
self.net.session.request.return_value = self.response
# pylint: disable=protected-access
self.assertEqual(self.response, self.net._send_request(
'HEAD', 'url', 'foo', bar='baz'))
mock_requests.request.assert_called_once_with(
'HEAD', 'url', 'foo', verify=mock.ANY, bar='baz', headers=mock.ANY)
'HEAD', 'http://example.com/', 'foo', bar='baz'))
self.net.session.request.assert_called_once_with(
'HEAD', 'http://example.com/', 'foo',
headers=mock.ANY, verify=mock.ANY, bar='baz')
@mock.patch('acme.client.requests')
def test_send_request_verify_ssl(self, mock_requests):
def test_send_request_verify_ssl(self):
# pylint: disable=protected-access
for verify in True, False:
mock_requests.request.reset_mock()
mock_requests.request.return_value = self.response
self.net.session = mock.MagicMock()
self.net.session.request.return_value = self.response
self.net.verify_ssl = verify
# pylint: disable=protected-access
self.assertEqual(
self.response, self.net._send_request('GET', 'url'))
mock_requests.request.assert_called_once_with(
'GET', 'url', verify=verify, headers=mock.ANY)
self.response,
self.net._send_request('GET', 'http://example.com/'))
self.net.session.request.assert_called_once_with(
'GET', 'http://example.com/', verify=verify, headers=mock.ANY)
@mock.patch('acme.client.requests')
def test_send_request_user_agent(self, mock_requests):
mock_requests.request.return_value = self.response
def test_send_request_user_agent(self):
self.net.session = mock.MagicMock()
# pylint: disable=protected-access
self.net._send_request('GET', 'url', headers={'bar': 'baz'})
mock_requests.request.assert_called_once_with(
'GET', 'url', verify=mock.ANY,
self.net._send_request('GET', 'http://example.com/',
headers={'bar': 'baz'})
self.net.session.request.assert_called_once_with(
'GET', 'http://example.com/', verify=mock.ANY,
headers={'User-Agent': 'acme-python-test', 'bar': 'baz'})
self.net._send_request('GET', 'url', headers={'User-Agent': 'foo2'})
mock_requests.request.assert_called_with(
'GET', 'url', verify=mock.ANY, headers={'User-Agent': 'foo2'})
self.net._send_request('GET', 'http://example.com/',
headers={'User-Agent': 'foo2'})
self.net.session.request.assert_called_with(
'GET', 'http://example.com/',
verify=mock.ANY, headers={'User-Agent': 'foo2'})
def test_del(self):
sess = mock.MagicMock()
self.net.session = sess
del self.net
sess.close.assert_called_once_with()
@mock.patch('acme.client.requests')
def test_requests_error_passthrough(self, mock_requests):
@ -614,14 +625,16 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase):
return self.checked_response
def test_head(self):
self.assertEqual(self.response, self.net.head('url', 'foo', bar='baz'))
self.assertEqual(self.response, self.net.head(
'http://example.com/', 'foo', bar='baz'))
self.send_request.assert_called_once_with(
'HEAD', 'url', 'foo', bar='baz')
'HEAD', 'http://example.com/', 'foo', bar='baz')
def test_get(self):
self.assertEqual(self.checked_response, self.net.get(
'url', content_type=self.content_type, bar='baz'))
self.send_request.assert_called_once_with('GET', 'url', bar='baz')
'http://example.com/', content_type=self.content_type, bar='baz'))
self.send_request.assert_called_once_with(
'GET', 'http://example.com/', bar='baz')
def test_post(self):
# pylint: disable=protected-access

View file

@ -1,4 +1,5 @@
"""Crypto utilities."""
import binascii
import contextlib
import logging
import re
@ -203,7 +204,7 @@ def gen_ss_cert(key, domains, not_before=None,
"""
assert domains, "Must provide one or more hostnames for the cert."
cert = OpenSSL.crypto.X509()
cert.set_serial_number(1337)
cert.set_serial_number(int(binascii.hexlify(OpenSSL.rand.bytes(16)), 16))
cert.set_version(2)
extensions = [

View file

@ -8,6 +8,8 @@ import unittest
import six
from six.moves import socketserver # pylint: disable=import-error
import OpenSSL
from acme import errors
from acme import jose
from acme import test_util
@ -126,5 +128,23 @@ class PyOpenSSLCertOrReqSANTest(unittest.TestCase):
self._get_idn_names())
class RandomSnTest(unittest.TestCase):
"""Test for random certificate serial numbers."""
def setUp(self):
self.cert_count = 5
self.serial_num = []
self.key = OpenSSL.crypto.PKey()
self.key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
def test_sn_collisions(self):
from acme.crypto_util import gen_ss_cert
for _ in range(self.cert_count):
cert = gen_ss_cert(self.key, ['dummy'], force_san=True)
self.serial_num.append(cert.get_serial_number())
self.assertTrue(len(set(self.serial_num)) > 1)
if __name__ == '__main__':
unittest.main() # pragma: no cover

View file

@ -37,9 +37,9 @@ class Error(jose.JSONObjectWithFields, errors.Error):
)
)
typ = jose.Field('type')
typ = jose.Field('type', omitempty=True, default='about:blank')
title = jose.Field('title', omitempty=True)
detail = jose.Field('detail')
detail = jose.Field('detail', omitempty=True)
@property
def description(self):
@ -123,6 +123,12 @@ class Directory(jose.JSONDeSerializable):
_REGISTERED_TYPES = {}
class Meta(jose.JSONObjectWithFields):
"""Directory Meta."""
terms_of_service = jose.Field('terms-of-service', omitempty=True)
website = jose.Field('website', omitempty=True)
caa_identities = jose.Field('caa-identities', omitempty=True)
@classmethod
def _canon_key(cls, key):
return getattr(key, 'resource_type', key)
@ -137,11 +143,6 @@ class Directory(jose.JSONDeSerializable):
def __init__(self, jobj):
canon_jobj = util.map_keys(jobj, self._canon_key)
if not set(canon_jobj).issubset(self._REGISTERED_TYPES):
# TODO: acme-spec is not clear about this: 'It is a JSON
# dictionary, whose keys are the "resource" values listed
# in {{https-requests}}'z
raise ValueError('Wrong directory fields')
# TODO: check that everything is an absolute URL; acme-spec is
# not clear on that
self._jobj = canon_jobj
@ -163,10 +164,8 @@ class Directory(jose.JSONDeSerializable):
@classmethod
def from_json(cls, jobj):
try:
return cls(jobj)
except ValueError as error:
raise jose.DeserializationError(str(error))
jobj['meta'] = cls.Meta.from_json(jobj.pop('meta', {}))
return cls(jobj)
class Resource(jose.JSONObjectWithFields):

View file

@ -28,6 +28,14 @@ class ErrorTest(unittest.TestCase):
self.error_custom = Error(typ='custom', detail='bar')
self.jobj_cusom = {'type': 'custom', 'detail': 'bar'}
def test_default_typ(self):
from acme.messages import Error
self.assertEqual(Error().typ, 'about:blank')
def test_from_json_empty(self):
from acme.messages import Error
self.assertEqual(Error(), Error.from_json('{}'))
def test_from_json_hashable(self):
from acme.messages import Error
hash(Error.from_json(self.error.to_json()))
@ -90,11 +98,16 @@ class DirectoryTest(unittest.TestCase):
self.dir = Directory({
'new-reg': 'reg',
mock.MagicMock(resource_type='new-cert'): 'cert',
'meta': Directory.Meta(
terms_of_service='https://example.com/acme/terms',
website='https://www.example.com/',
caa_identities=['example.com'],
),
})
def test_init_wrong_key_value_error(self):
def test_init_wrong_key_value_success(self): # pylint: disable=no-self-use
from acme.messages import Directory
self.assertRaises(ValueError, Directory, {'foo': 'bar'})
Directory({'foo': 'bar'})
def test_getitem(self):
self.assertEqual('reg', self.dir['new-reg'])
@ -111,14 +124,20 @@ class DirectoryTest(unittest.TestCase):
def test_getattr_fails_with_attribute_error(self):
self.assertRaises(AttributeError, self.dir.__getattr__, 'foo')
def test_to_partial_json(self):
self.assertEqual(
self.dir.to_partial_json(), {'new-reg': 'reg', 'new-cert': 'cert'})
def test_to_json(self):
self.assertEqual(self.dir.to_json(), {
'new-reg': 'reg',
'new-cert': 'cert',
'meta': {
'terms-of-service': 'https://example.com/acme/terms',
'website': 'https://www.example.com/',
'caa-identities': ['example.com'],
},
})
def test_from_json_deserialization_error_on_wrong_key(self):
def test_from_json_deserialization_unknown_key_success(self): # pylint: disable=no-self-use
from acme.messages import Directory
self.assertRaises(
jose.DeserializationError, Directory.from_json, {'foo': 'bar'})
Directory.from_json({'foo': 'bar'})
class RegistrationTest(unittest.TestCase):

View file

@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.5.0.dev0'
version = '0.9.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
@ -53,7 +53,7 @@ setup(
version=version,
description='ACME protocol implementation in Python',
url='https://github.com/letsencrypt/letsencrypt',
author="Let's Encrypt Project",
author="Certbot Project",
author_email='client-dev@letsencrypt.org',
license='Apache License 2.0',
classifiers=[

View file

@ -0,0 +1,7 @@
include LICENSE.txt
include README.rst
recursive-include docs *
recursive-include certbot_apache/tests/testdata *
include certbot_apache/centos-options-ssl-apache.conf
include certbot_apache/options-ssl-apache.conf
recursive-include certbot_apache/augeas_lens *.aug

View file

@ -0,0 +1 @@
Apache plugin for Certbot

View file

@ -0,0 +1 @@
"""Certbot Apache plugin."""

View file

@ -1,13 +1,12 @@
"""Class of Augeas Configurators."""
import logging
import augeas
from letsencrypt import errors
from letsencrypt import reverter
from letsencrypt.plugins import common
from certbot import errors
from certbot import reverter
from certbot.plugins import common
from letsencrypt_apache import constants
from certbot_apache import constants
logger = logging.getLogger(__name__)
@ -16,25 +15,22 @@ class AugeasConfigurator(common.Plugin):
"""Base Augeas Configurator class.
:ivar config: Configuration.
:type config: :class:`~letsencrypt.interfaces.IConfig`
:type config: :class:`~certbot.interfaces.IConfig`
:ivar aug: Augeas object
:type aug: :class:`augeas.Augeas`
:ivar str save_notes: Human-readable configuration change notes
:ivar reverter: saves and reverts checkpoints
:type reverter: :class:`letsencrypt.reverter.Reverter`
:type reverter: :class:`certbot.reverter.Reverter`
"""
def __init__(self, *args, **kwargs):
super(AugeasConfigurator, self).__init__(*args, **kwargs)
self.aug = augeas.Augeas(
# specify a directory to load our preferred lens from
loadpath=constants.AUGEAS_LENS_DIR,
# Do not save backup (we do it ourselves), do not load
# anything by default
flags=(augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD))
# Placeholder for augeas
self.aug = None
self.save_notes = ""
# See if any temporary changes need to be recovered
@ -42,6 +38,16 @@ class AugeasConfigurator(common.Plugin):
# because this will change the underlying configuration and potential
# vhosts
self.reverter = reverter.Reverter(self.config)
def init_augeas(self):
""" Initialize the actual Augeas instance """
import augeas
self.aug = augeas.Augeas(
# specify a directory to load our preferred lens from
loadpath=constants.AUGEAS_LENS_DIR,
# Do not save backup (we do it ourselves), do not load
# anything by default
flags=(augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD))
self.recovery_routine()
def check_parsing_errors(self, lens):

View file

@ -0,0 +1,2 @@
Certbot includes the very latest Augeas lenses in order to ship bug fixes
to Apache configuration handling bugs as quickly as possible

View file

@ -45,21 +45,24 @@ autoload xfm
let dels (s:string) = del s s
(* deal with continuation lines *)
let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "
let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)/ ""
let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)+/ " "
let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)*/ ""
let sep_eq = del /[ \t]*=[ \t]*/ "="
let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
let word = /[a-z][a-z0-9._-]*/i
let comment = Util.comment
let eol = Util.doseol
let empty = Util.empty_dos
let indent = Util.indent
let comment_val_re = /([^ \t\r\n](.|\\\\\r?\n)*[^ \\\t\r\n]|[^ \t\r\n])/
let comment = [ label "#comment" . del /[ \t]*#[ \t]*/ "# "
. store comment_val_re . eol ]
(* borrowed from shellvars.aug *)
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'/
let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'/
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'|\\\\ /
let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ /
let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
let cdot = /\\\\./

View file

@ -13,18 +13,18 @@ import zope.interface
from acme import challenges
from letsencrypt import errors
from letsencrypt import interfaces
from letsencrypt import le_util
from certbot import errors
from certbot import interfaces
from certbot import util
from letsencrypt.plugins import common
from certbot.plugins import common
from letsencrypt_apache import augeas_configurator
from letsencrypt_apache import constants
from letsencrypt_apache import display_ops
from letsencrypt_apache import tls_sni_01
from letsencrypt_apache import obj
from letsencrypt_apache import parser
from certbot_apache import augeas_configurator
from certbot_apache import constants
from certbot_apache import display_ops
from certbot_apache import tls_sni_01
from certbot_apache import obj
from certbot_apache import parser
from collections import defaultdict
@ -70,14 +70,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
14.04 Apache 2.4 and it works for Ubuntu 12.04 Apache 2.2
:ivar config: Configuration.
:type config: :class:`~letsencrypt.interfaces.IConfig`
:type config: :class:`~certbot.interfaces.IConfig`
:ivar parser: Handles low level parsing
:type parser: :class:`~letsencrypt_apache.parser`
:type parser: :class:`~certbot_apache.parser`
:ivar tup version: version of Apache
:ivar list vhosts: All vhosts found in the configuration
(:class:`list` of :class:`~letsencrypt_apache.obj.VirtualHost`)
(:class:`list` of :class:`~certbot_apache.obj.VirtualHost`)
:ivar dict assoc: Mapping between domains and vhosts
@ -106,8 +106,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
add("handle-sites", default=constants.os_constant("handle_sites"),
help="Let installer handle enabling sites for you." +
"(Only Ubuntu/Debian currently)")
le_util.add_deprecated_argument(add, argument_name="ctl", nargs=1)
le_util.add_deprecated_argument(
util.add_deprecated_argument(add, argument_name="ctl", nargs=1)
util.add_deprecated_argument(
add, argument_name="init-script", nargs=1)
def __init__(self, *args, **kwargs):
@ -124,13 +124,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.assoc = dict()
# Outstanding challenges
self._chall_out = set()
# Maps enhancements to vhosts we've enabled the enhancement for
self._enhanced_vhosts = defaultdict(set)
# These will be set in the prepare function
self.parser = None
self.version = version
self.vhosts = None
self._enhance_func = {"redirect": self._enable_redirect,
"ensure-http-header": self._set_http_header}
"ensure-http-header": self._set_http_header,
"staple-ocsp": self._enable_ocsp_stapling}
@property
def mod_ssl_conf(self):
@ -147,8 +150,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:raises .errors.PluginError: If there is any other error
"""
# Perform the actual Augeas initialization to be able to react
try:
self.init_augeas()
except ImportError:
raise errors.NoInstallationError("Problem in Augeas installation")
# Verify Apache is installed
if not le_util.exe_exists(constants.os_constant("restart_cmd")[0]):
if not util.exe_exists(constants.os_constant("restart_cmd")[0]):
raise errors.NoInstallationError
# Make sure configuration is valid
@ -205,7 +214,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
installed, the VirtualHost is enabled if it isn't already.
.. todo:: Might be nice to remove chain directive if none exists
This shouldn't happen within letsencrypt though
This shouldn't happen within certbot though
:raises errors.PluginError: When unable to deploy certificate due to
a lack of directives
@ -290,7 +299,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param bool temp: whether the vhost is only used temporarily
:returns: ssl vhost associated with name
:rtype: :class:`~letsencrypt_apache.obj.VirtualHost`
:rtype: :class:`~certbot_apache.obj.VirtualHost`
:raises .errors.PluginError: If no vhost is available or chosen
@ -472,7 +481,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Helper function for get_virtual_hosts().
:param host: In progress vhost whose names will be added
:type host: :class:`~letsencrypt_apache.obj.VirtualHost`
:type host: :class:`~certbot_apache.obj.VirtualHost`
"""
# Take the final ServerName as each overrides the previous
@ -498,7 +507,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str path: Augeas path to virtual host
:returns: newly created vhost
:rtype: :class:`~letsencrypt_apache.obj.VirtualHost`
:rtype: :class:`~certbot_apache.obj.VirtualHost`
"""
addrs = set()
@ -534,7 +543,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def get_virtual_hosts(self):
"""Returns list of virtual hosts found in the Apache configuration.
:returns: List of :class:`~letsencrypt_apache.obj.VirtualHost`
:returns: List of :class:`~certbot_apache.obj.VirtualHost`
objects found in configuration
:rtype: list
@ -572,7 +581,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
now NameVirtualHosts. If version is earlier than 2.4, check if addr
has a NameVirtualHost directive in the Apache config
:param letsencrypt_apache.obj.Addr target_addr: vhost address
:param certbot_apache.obj.Addr target_addr: vhost address
:returns: Success
:rtype: bool
@ -590,11 +599,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Adds NameVirtualHost directive for given address.
:param addr: Address that will be added as NameVirtualHost directive
:type addr: :class:`~letsencrypt_apache.obj.Addr`
:type addr: :class:`~certbot_apache.obj.Addr`
"""
loc = parser.get_aug_path(self.parser.loc["name"])
loc = parser.get_aug_path(self.parser.loc["name"])
if addr.get_port() == "443":
path = self.parser.add_dir_to_ifmodssl(
loc, "NameVirtualHost", [str(addr)])
@ -679,7 +688,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Checks to see if the server is ready for SNI challenges.
:param addrs: Addresses to check SNI compatibility
:type addrs: :class:`~letsencrypt_apache.obj.Addr`
:type addrs: :class:`~certbot_apache.obj.Addr`
"""
# Version 2.4 and later are automatically SNI ready.
@ -697,15 +706,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Duplicates vhost and adds default ssl options
New vhost will reside as (nonssl_vhost.path) +
``letsencrypt_apache.constants.os_constant("le_vhost_ext")``
``certbot_apache.constants.os_constant("le_vhost_ext")``
.. note:: This function saves the configuration
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
:type nonssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type nonssl_vhost: :class:`~certbot_apache.obj.VirtualHost`
:returns: SSL vhost
:rtype: :class:`~letsencrypt_apache.obj.VirtualHost`
:rtype: :class:`~certbot_apache.obj.VirtualHost`
:raises .errors.PluginError: If more than one virtual host is in
the file or if plugin is unable to write/read vhost files.
@ -911,7 +920,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
https://httpd.apache.org/docs/2.2/mod/core.html#namevirtualhost
:param vhost: New virtual host that was recently created.
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
"""
need_to_save = False
@ -944,16 +953,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
######################################################################
def supported_enhancements(self): # pylint: disable=no-self-use
"""Returns currently supported enhancements."""
return ["redirect", "ensure-http-header"]
return ["redirect", "ensure-http-header", "staple-ocsp"]
def enhance(self, domain, enhancement, options=None):
"""Enhance configuration.
:param str domain: domain to enhance
:param str enhancement: enhancement type defined in
:const:`~letsencrypt.constants.ENHANCEMENTS`
:const:`~certbot.constants.ENHANCEMENTS`
:param options: options for the enhancement
See :const:`~letsencrypt.constants.ENHANCEMENTS`
See :const:`~certbot.constants.ENHANCEMENTS`
documentation for appropriate parameter.
:raises .errors.PluginError: If Enhancement is not supported, or if
@ -971,6 +980,68 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
logger.warn("Failed %s for %s", enhancement, domain)
raise
def _enable_ocsp_stapling(self, ssl_vhost, unused_options):
"""Enables OCSP Stapling
In OCSP, each client (e.g. browser) would have to query the
OCSP Responder to validate that the site certificate was not revoked.
Enabling OCSP Stapling, would allow the web-server to query the OCSP
Responder, and staple its response to the offered certificate during
TLS. i.e. clients would not have to query the OCSP responder.
OCSP Stapling enablement on Apache implicitly depends on
SSLCertificateChainFile being set by other code.
.. note:: This function saves the configuration
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:param unused_options: Not currently used
:type unused_options: Not Available
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)
"""
min_apache_ver = (2, 3, 3)
if self.get_version() < min_apache_ver:
raise errors.PluginError(
"Unable to set OCSP directives.\n"
"Apache version is below 2.3.3.")
if "socache_shmcb_module" not in self.parser.modules:
self.enable_mod("socache_shmcb")
# Check if there's an existing SSLUseStapling directive on.
use_stapling_aug_path = self.parser.find_dir("SSLUseStapling",
"on", start=ssl_vhost.path)
if not use_stapling_aug_path:
self.parser.add_dir(ssl_vhost.path, "SSLUseStapling", "on")
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
# Check if there's an existing SSLStaplingCache directive.
stapling_cache_aug_path = self.parser.find_dir('SSLStaplingCache',
None, ssl_vhost_aug_path)
# We'll simply delete the directive, so that we'll have a
# consistent OCSP cache path.
if stapling_cache_aug_path:
self.aug.remove(
re.sub(r"/\w*$", "", stapling_cache_aug_path[0]))
self.parser.add_dir_to_ifmodssl(ssl_vhost_aug_path,
"SSLStaplingCache",
["shmcb:/var/run/apache2/stapling_cache(128000)"])
msg = "OCSP Stapling was enabled on SSL Vhost: %s.\n"%(
ssl_vhost.filep)
self.save_notes += msg
self.save()
logger.info(msg)
def _set_http_header(self, ssl_vhost, header_substring):
"""Enables header that is identified by header_substring on ssl_vhost.
@ -981,14 +1052,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. note:: This function saves the configuration
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type ssl_vhost: :class:`~certbot_apache.obj.VirtualHost`
:param header_substring: string that uniquely identifies a header.
e.g: Strict-Transport-Security, Upgrade-Insecure-Requests.
:type str
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)
:rtype: (bool, :class:`~certbot_apache.obj.VirtualHost`)
:raises .errors.PluginError: If no viable HTTP host can be created or
set with header header_substring.
@ -1016,7 +1087,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
contains the string header_substring.
:param ssl_vhost: vhost to check
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
:param header_substring: string that uniquely identifies a header.
e.g: Strict-Transport-Security, Upgrade-Insecure-Requests.
@ -1053,14 +1124,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. note:: This function saves the configuration
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type ssl_vhost: :class:`~certbot_apache.obj.VirtualHost`
:param unused_options: Not currently used
:type unused_options: Not Available
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)
:raises .errors.PluginError: If no viable HTTP host can be created or
used for the redirect.
@ -1083,11 +1151,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"redirection")
self._create_redirect_vhost(ssl_vhost)
else:
# Check if LetsEncrypt redirection already exists
self._verify_no_letsencrypt_redirect(general_vh)
if general_vh in self._enhanced_vhosts["redirect"]:
logger.debug("Already enabled redirect for this vhost")
return
# Check if Certbot redirection already exists
self._verify_no_certbot_redirect(general_vh)
# Note: if code flow gets here it means we didn't find the exact
# letsencrypt RewriteRule config for redirection. Finding
# certbot RewriteRule config for redirection. Finding
# another RewriteRule is likely to be fine in most or all cases,
# but redirect loops are possible in very obscure cases; see #1620
# for reasoning.
@ -1118,20 +1190,21 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
(general_vh.filep, ssl_vhost.filep))
self.save()
self._enhanced_vhosts["redirect"].add(general_vh)
logger.info("Redirecting vhost in %s to ssl vhost in %s",
general_vh.filep, ssl_vhost.filep)
def _verify_no_letsencrypt_redirect(self, vhost):
"""Checks to see if a redirect was already installed by letsencrypt.
def _verify_no_certbot_redirect(self, vhost):
"""Checks to see if a redirect was already installed by certbot.
Checks to see if virtualhost already contains a rewrite rule that is
identical to Letsencrypt's redirection rewrite rule.
identical to Certbot's redirection rewrite rule.
:param vhost: vhost to check
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
:raises errors.PluginEnhancementAlreadyPresent: When the exact
letsencrypt redirection WriteRule exists in virtual host.
certbot redirection WriteRule exists in virtual host.
"""
rewrite_path = self.parser.find_dir(
"RewriteRule", None, start=vhost.path)
@ -1154,13 +1227,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
for matches in rewrite_args_dict.values():
if [self.aug.get(x) for x in matches] in redirect_args:
raise errors.PluginEnhancementAlreadyPresent(
"Let's Encrypt has already enabled redirection")
"Certbot has already enabled redirection")
def _is_rewrite_exists(self, vhost):
"""Checks if there exists a RewriteRule directive in vhost
:param vhost: vhost to check
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
:returns: True if a RewriteRule directive exists.
:rtype: bool
@ -1174,23 +1247,27 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Checks if a RewriteEngine directive is on
:param vhost: vhost to check
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
"""
rewrite_engine_path = self.parser.find_dir("RewriteEngine", "on",
rewrite_engine_path_list = self.parser.find_dir("RewriteEngine", "on",
start=vhost.path)
if rewrite_engine_path:
return self.parser.get_arg(rewrite_engine_path[0])
if rewrite_engine_path_list:
for re_path in rewrite_engine_path_list:
# A RewriteEngine directive may also be included in per
# directory .htaccess files. We only care about the VirtualHost.
if 'VirtualHost' in re_path:
return self.parser.get_arg(re_path)
return False
def _create_redirect_vhost(self, ssl_vhost):
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
:param ssl_vhost: ssl vhost
:type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type ssl_vhost: :class:`~certbot_apache.obj.VirtualHost`
:returns: tuple of the form
(`success`, :class:`~letsencrypt_apache.obj.VirtualHost`)
(`success`, :class:`~certbot_apache.obj.VirtualHost`)
:rtype: tuple
"""
@ -1202,6 +1279,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Make a new vhost data structure and add it to the lists
new_vhost = self._create_vhost(parser.get_aug_path(redirect_filepath))
self.vhosts.append(new_vhost)
self._enhanced_vhosts["redirect"].add(new_vhost)
# Finally create documentation for the change
self.save_notes += ("Created a port 80 vhost, %s, for redirection to "
@ -1369,7 +1447,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. todo:: Make sure link is not broken...
:param vhost: vhost to enable
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
:raises .errors.NotSupportedError: If filesystem layout is not
supported.
@ -1449,14 +1527,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Generate reversal command.
# Try to be safe here... check that we can probably reverse before
# applying enmod command
if not le_util.exe_exists(self.conf("dismod")):
if not util.exe_exists(self.conf("dismod")):
raise errors.MisconfigurationError(
"Unable to find a2dismod, please make sure a2enmod and "
"a2dismod are configured correctly for letsencrypt.")
"a2dismod are configured correctly for certbot.")
self.reverter.register_undo_command(
temp, [self.conf("dismod"), mod_name])
le_util.run_script([self.conf("enmod"), mod_name])
util.run_script([self.conf("enmod"), mod_name])
def restart(self):
"""Runs a config test and reloads the Apache server.
@ -1475,7 +1553,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
le_util.run_script(constants.os_constant("restart_cmd"))
util.run_script(constants.os_constant("restart_cmd"))
except errors.SubprocessError as err:
raise errors.MisconfigurationError(str(err))
@ -1486,7 +1564,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
le_util.run_script(constants.os_constant("conftest_cmd"))
util.run_script(constants.os_constant("conftest_cmd"))
except errors.SubprocessError as err:
raise errors.MisconfigurationError(str(err))
@ -1502,8 +1580,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
stdout, _ = le_util.run_script(
constants.os_constant("version_cmd"))
stdout, _ = util.run_script(constants.os_constant("version_cmd"))
except errors.SubprocessError:
raise errors.PluginError(
"Unable to run %s -v" %
@ -1635,11 +1712,11 @@ def get_file_path(vhost_path):
def install_ssl_options_conf(options_ssl):
"""
Copy Let's Encrypt's SSL options file into the system's config dir if
Copy Certbot's SSL options file into the system's config dir if
required.
"""
# XXX if we ever try to enforce a local privilege boundary (eg, running
# letsencrypt for unprivileged users via setuid), this function will need
# certbot for unprivileged users via setuid), this function will need
# to be modified.
# XXX if the user is in security-autoupdate mode, we should be willing to

View file

@ -1,6 +1,6 @@
"""Apache plugin constants."""
import pkg_resources
from letsencrypt import le_util
from certbot import util
CLI_DEFAULTS_DEBIAN = dict(
@ -18,7 +18,7 @@ CLI_DEFAULTS_DEBIAN = dict(
handle_sites=True,
challenge_location="/etc/apache2",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"letsencrypt_apache", "options-ssl-apache.conf")
"certbot_apache", "options-ssl-apache.conf")
)
CLI_DEFAULTS_CENTOS = dict(
server_root="/etc/httpd",
@ -35,7 +35,7 @@ CLI_DEFAULTS_CENTOS = dict(
handle_sites=False,
challenge_location="/etc/httpd/conf.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"letsencrypt_apache", "centos-options-ssl-apache.conf")
"certbot_apache", "centos-options-ssl-apache.conf")
)
CLI_DEFAULTS_GENTOO = dict(
server_root="/etc/apache2",
@ -52,7 +52,7 @@ CLI_DEFAULTS_GENTOO = dict(
handle_sites=False,
challenge_location="/etc/apache2/vhosts.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"letsencrypt_apache", "options-ssl-apache.conf")
"certbot_apache", "options-ssl-apache.conf")
)
CLI_DEFAULTS_DARWIN = dict(
server_root="/etc/apache2",
@ -69,7 +69,7 @@ CLI_DEFAULTS_DARWIN = dict(
handle_sites=False,
challenge_location="/etc/apache2/other",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"letsencrypt_apache", "options-ssl-apache.conf")
"certbot_apache", "options-ssl-apache.conf")
)
CLI_DEFAULTS = {
"debian": CLI_DEFAULTS_DEBIAN,
@ -78,6 +78,9 @@ CLI_DEFAULTS = {
"centos linux": CLI_DEFAULTS_CENTOS,
"fedora": CLI_DEFAULTS_CENTOS,
"red hat enterprise linux server": CLI_DEFAULTS_CENTOS,
"rhel": CLI_DEFAULTS_CENTOS,
"amazon": CLI_DEFAULTS_CENTOS,
"gentoo": CLI_DEFAULTS_GENTOO,
"gentoo base system": CLI_DEFAULTS_GENTOO,
"darwin": CLI_DEFAULTS_DARWIN,
}
@ -87,7 +90,7 @@ MOD_SSL_CONF_DEST = "options-ssl-apache.conf"
"""Name of the mod_ssl config file as saved in `IConfig.config_dir`."""
AUGEAS_LENS_DIR = pkg_resources.resource_filename(
"letsencrypt_apache", "augeas_lens")
"certbot_apache", "augeas_lens")
"""Path to the Augeas lens directory"""
REWRITE_HTTPS_ARGS = [
@ -116,7 +119,7 @@ def os_constant(key):
:param key: name of cli constant
:return: value of constant for active os
"""
os_info = le_util.get_os_info()
os_info = util.get_os_info()
try:
constants = CLI_DEFAULTS[os_info[0].lower()]
except KeyError:

View file

@ -4,10 +4,10 @@ import os
import zope.component
from letsencrypt import errors
from letsencrypt import interfaces
from certbot import errors
from certbot import interfaces
import letsencrypt.display.util as display_util
import certbot.display.util as display_util
logger = logging.getLogger(__name__)
@ -50,7 +50,7 @@ def _vhost_menu(domain, vhosts):
if free_chars < 2:
logger.debug("Display size is too small for "
"letsencrypt_apache.display_ops._vhost_menu()")
"certbot_apache.display_ops._vhost_menu()")
# This runs the edge off the screen, but it doesn't cause an "error"
filename_size = 1
disp_name_size = 1

View file

@ -1,7 +1,7 @@
"""Module contains classes used by the Apache Configurator."""
import re
from letsencrypt.plugins import common
from certbot.plugins import common
class Addr(common.Addr):

View file

@ -6,9 +6,9 @@ import os
import re
import subprocess
from letsencrypt import errors
from certbot import errors
from letsencrypt_apache import constants
from certbot_apache import constants
logger = logging.getLogger(__name__)

View file

@ -0,0 +1 @@
"""Certbot Apache Tests"""

View file

@ -0,0 +1,6 @@
Issues for which some kind of test case should be constructable, but we do not
currently have one:
https://github.com/certbot/certbot/issues/1213
https://github.com/certbot/certbot/issues/1602

View file

@ -5,9 +5,7 @@
export EA=/etc/apache2/
TESTDIR="`dirname $0`"
LEROOT="`realpath \"$TESTDIR/../../../../\"`"
cd $TESTDIR/passing
LETSENCRYPT="${LETSENCRYPT:-$LEROOT/venv/bin/letsencrypt}"
function CleanupExit() {
echo control c, exiting tests...
@ -21,13 +19,13 @@ function Setup() {
if [ "$APPEND_APACHECONF" = "" ] ; then
sudo cp "$f" "$EA"/sites-available/
sudo ln -sf "$EA/sites-available/$f" "$EA/sites-enabled/$f"
sudo echo """
echo "
<VirtualHost *:80>
ServerName example.com
DocumentRoot /tmp/
ErrorLog /tmp/error.log
CustomLog /tmp/requests.log combined
</VirtualHost>""" >> $EA/sites-available/throwaway-example.conf
</VirtualHost>" | sudo tee $EA/sites-available/throwaway-example.conf >/dev/null
else
TMP="/tmp/`basename \"$APPEND_APACHECONF\"`.$$"
sudo cp -a "$APPEND_APACHECONF" "$TMP"
@ -61,7 +59,7 @@ trap CleanupExit INT
for f in *.conf ; do
echo -n testing "$f"...
Setup
RESULT=`echo c | sudo "$LETSENCRYPT" -vvvv --debug --staging --apache --register-unsafely-without-email --agree-tos certonly -t 2>&1`
RESULT=`echo c | sudo $(command -v certbot) -vvvv --debug --staging --apache --register-unsafely-without-email --agree-tos certonly -t 2>&1`
if echo $RESULT | grep -Eq \("Which names would you like"\|"mod_macro is not yet"\) ; then
echo passed
else

View file

@ -0,0 +1,428 @@
# ---------------------------------------------------------------
# Core ModSecurity Rule Set ver.2.2.6
# Copyright (C) 2006-2012 Trustwave All rights reserved.
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENCE file for full details.
# ---------------------------------------------------------------
#
# -- [[ Recommended Base Configuration ]] -------------------------------------------------
#
# The configuration directives/settings in this file are used to control
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
# ModSecurity settings such as:
#
# - SecRuleEngine
# - SecRequestBodyAccess
# - SecAuditEngine
# - SecDebugLog
#
# You should use the modsecurity.conf-recommended file that comes with the
# ModSecurity source code archive.
#
# Ref: http://mod-security.svn.sourceforge.net/viewvc/mod-security/m2/trunk/modsecurity.conf-recommended
#
#
# -- [[ Rule Version ]] -------------------------------------------------------------------
#
# Rule version data is added to the "Producer" line of Section H of the Audit log:
#
# - Producer: ModSecurity for Apache/2.7.0-rc1 (http://www.modsecurity.org/); OWASP_CRS/2.2.4.
#
# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecComponentSignature
#
#SecComponentSignature "OWASP_CRS/2.2.6"
#
# -- [[ Modes of Operation: Self-Contained vs. Collaborative Detection ]] -----------------
#
# Each detection rule uses the "block" action which will inherit the SecDefaultAction
# specified below. Your settings here will determine which mode of operation you use.
#
# -- [[ Self-Contained Mode ]] --
# Rules inherit the "deny" disruptive action. The first rule that matches will block.
#
# -- [[ Collaborative Detection Mode ]] --
# This is a "delayed blocking" mode of operation where each matching rule will inherit
# the "pass" action and will only contribute to anomaly scores. Transactional blocking
# can be applied
#
# -- [[ Alert Logging Control ]] --
# You have three options -
#
# - To log to both the Apache error_log and ModSecurity audit_log file use: "log"
# - To log *only* to the ModSecurity audit_log file use: "nolog,auditlog"
# - To log *only* to the Apache error_log file use: "log,noauditlog"
#
# Ref: http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-traditional-vs-anomaly-scoring-detection-modes.html
# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecDefaultAction
#
#SecDefaultAction "phase:1,deny,log"
#
# -- [[ Collaborative Detection Severity Levels ]] ----------------------------------------
#
# These are the default scoring points for each severity level. You may
# adjust these to you liking. These settings will be used in macro expansion
# in the rules to increment the anomaly scores when rules match.
#
# These are the default Severity ratings (with anomaly scores) of the individual rules -
#
# - 2: Critical - Anomaly Score of 5.
# Is the highest severity level possible without correlation. It is
# normally generated by the web attack rules (40 level files).
# - 3: Error - Anomaly Score of 4.
# Is generated mostly from outbound leakage rules (50 level files).
# - 4: Warning - Anomaly Score of 3.
# Is generated by malicious client rules (35 level files).
# - 5: Notice - Anomaly Score of 2.
# Is generated by the Protocol policy and anomaly files.
#
#SecAction \
"id:'900001', \
phase:1, \
t:none, \
setvar:tx.critical_anomaly_score=5, \
setvar:tx.error_anomaly_score=4, \
setvar:tx.warning_anomaly_score=3, \
setvar:tx.notice_anomaly_score=2, \
nolog, \
pass"
#
# -- [[ Collaborative Detection Scoring Threshold Levels ]] ------------------------------
#
# These variables are used in macro expansion in the 49 inbound blocking and 59
# outbound blocking files.
#
# **MUST HAVE** ModSecurity v2.5.12 or higher to use macro expansion in numeric
# operators. If you have an earlier version, edit the 49/59 files directly to
# set the appropriate anomaly score levels.
#
# You should set the score to the proper threshold you would prefer. If set to "5"
# it will work similarly to previous Mod CRS rules and will create an event in the error_log
# file if there are any rules that match. If you would like to lessen the number of events
# generated in the error_log file, you should increase the anomaly score threshold to
# something like "20". This would only generate an event in the error_log file if
# there are multiple lower severity rule matches or if any 1 higher severity item matches.
#
#SecAction \
"id:'900002', \
phase:1, \
t:none, \
setvar:tx.inbound_anomaly_score_level=5, \
nolog, \
pass"
#SecAction \
"id:'900003', \
phase:1, \
t:none, \
setvar:tx.outbound_anomaly_score_level=4, \
nolog, \
pass"
#
# -- [[ Collaborative Detection Blocking ]] -----------------------------------------------
#
# This is a collaborative detection mode where each rule will increment an overall
# anomaly score for the transaction. The scores are then evaluated in the following files:
#
# Inbound anomaly score - checked in the modsecurity_crs_49_inbound_blocking.conf file
# Outbound anomaly score - checked in the modsecurity_crs_59_outbound_blocking.conf file
#
# If you want to use anomaly scoring mode, then uncomment this line.
#
#SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \
pass"
#
# -- [[ GeoIP Database ]] -----------------------------------------------------------------
#
# There are some rulesets that need to inspect the GEO data of the REMOTE_ADDR data.
#
# You must first download the MaxMind GeoIP Lite City DB -
#
# http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
#
# You then need to define the proper path for the SecGeoLookupDb directive
#
# Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html
# Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html
#
#SecGeoLookupDb /opt/modsecurity/lib/GeoLiteCity.dat
#
# -- [[ Regression Testing Mode ]] --------------------------------------------------------
#
# If you are going to run the regression testing mode, you should uncomment the
# following rule. It will enable DetectionOnly mode for the SecRuleEngine and
# will enable Response Header tagging so that the client testing script can see
# which rule IDs have matched.
#
# You must specify the your source IP address where you will be running the tests
# from.
#
#SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \
"id:'900005', \
phase:1, \
t:none, \
ctl:ruleEngine=DetectionOnly, \
setvar:tx.regression_testing=1, \
nolog, \
pass"
#
# -- [[ HTTP Policy Settings ]] ----------------------------------------------------------
#
# Set the following policy settings here and they will be propagated to the 23 rules
# file (modsecurity_common_23_request_limits.conf) by using macro expansion.
# If you run into false positives, you can adjust the settings here.
#
# Only the max number of args is uncommented by default as there are a high rate
# of false positives. Uncomment the items you wish to set.
#
#
# -- Maximum number of arguments in request limited
#SecAction \
"id:'900006', \
phase:1, \
t:none, \
setvar:tx.max_num_args=255, \
nolog, \
pass"
#
# -- Limit argument name length
#SecAction \
"id:'900007', \
phase:1, \
t:none, \
setvar:tx.arg_name_length=100, \
nolog, \
pass"
#
# -- Limit value name length
#SecAction \
"id:'900008', \
phase:1, \
t:none, \
setvar:tx.arg_length=400, \
nolog, \
pass"
#
# -- Limit arguments total length
#SecAction \
"id:'900009', \
phase:1, \
t:none, \
setvar:tx.total_arg_length=64000, \
nolog, \
pass"
#
# -- Individual file size is limited
#SecAction \
"id:'900010', \
phase:1, \
t:none, \
setvar:tx.max_file_size=1048576, \
nolog, \
pass"
#
# -- Combined file size is limited
#SecAction \
"id:'900011', \
phase:1, \
t:none, \
setvar:tx.combined_file_sizes=1048576, \
nolog, \
pass"
#
# Set the following policy settings here and they will be propagated to the 30 rules
# file (modsecurity_crs_30_http_policy.conf) by using macro expansion.
# If you run into false positves, you can adjust the settings here.
#
#SecAction \
"id:'900012', \
phase:1, \
t:none, \
setvar:'tx.allowed_methods=GET HEAD POST OPTIONS', \
setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded|multipart/form-data|text/xml|application/xml|application/x-amf', \
setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \
setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', \
setvar:'tx.restricted_headers=/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/', \
nolog, \
pass"
#
# -- [[ Content Security Policy (CSP) Settings ]] -----------------------------------------
#
# The purpose of these settings is to send CSP response headers to
# Mozilla FireFox users so that you can enforce how dynamic content
# is used. CSP usage helps to prevent XSS attacks against your users.
#
# Reference Link:
#
# https://developer.mozilla.org/en/Security/CSP
#
# Uncomment this SecAction line if you want use CSP enforcement.
# You need to set the appropriate directives and settings for your site/domain and
# and activate the CSP file in the experimental_rules directory.
#
# Ref: http://blog.spiderlabs.com/2011/04/modsecurity-advanced-topic-of-the-week-integrating-content-security-policy-csp.html
#
#SecAction \
"id:'900013', \
phase:1, \
t:none, \
setvar:tx.csp_report_only=1, \
setvar:tx.csp_report_uri=/csp_violation_report, \
setenv:'csp_policy=allow \'self\'; img-src *.yoursite.com; media-src *.yoursite.com; style-src *.yoursite.com; frame-ancestors *.yoursite.com; script-src *.yoursite.com; report-uri %{tx.csp_report_uri}', \
nolog, \
pass"
#
# -- [[ Brute Force Protection ]] ---------------------------------------------------------
#
# If you are using the Brute Force Protection rule set, then uncomment the following
# lines and set the following variables:
# - Protected URLs: resources to protect (e.g. login pages) - set to your login page
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
#SecAction \
"id:'900014', \
phase:1, \
t:none, \
setvar:'tx.brute_force_protected_urls=/login.jsp /partner_login.php', \
setvar:'tx.brute_force_burst_time_slice=60', \
setvar:'tx.brute_force_counter_threshold=10', \
setvar:'tx.brute_force_block_timeout=300', \
nolog, \
pass"
#
# -- [[ DoS Protection ]] ----------------------------------------------------------------
#
# If you are using the DoS Protection rule set, then uncomment the following
# lines and set the following variables:
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
#SecAction \
"id:'900015', \
phase:1, \
t:none, \
setvar:'tx.dos_burst_time_slice=60', \
setvar:'tx.dos_counter_threshold=100', \
setvar:'tx.dos_block_timeout=600', \
nolog, \
pass"
#
# -- [[ Check UTF enconding ]] -----------------------------------------------------------
#
# We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise
# it will result in false positives.
#
# Uncomment this line if your site uses UTF8 encoding
#SecAction \
"id:'900016', \
phase:1, \
t:none, \
setvar:tx.crs_validate_utf8_encoding=1, \
nolog, \
pass"
#
# -- [[ Enable XML Body Parsing ]] -------------------------------------------------------
#
# The rules in this file will trigger the XML parser upon an XML request
#
# Initiate XML Processor in case of xml content-type
#
#SecRule REQUEST_HEADERS:Content-Type "text/xml" \
"id:'900017', \
phase:1, \
t:none,t:lowercase, \
nolog, \
pass, \
chain"
#SecRule REQBODY_PROCESSOR "!@streq XML" \
"ctl:requestBodyProcessor=XML"
#
# -- [[ Global and IP Collections ]] -----------------------------------------------------
#
# Create both Global and IP collections for rules to use
# There are some CRS rules that assume that these two collections
# have already been initiated.
#
#SecRule REQUEST_HEADERS:User-Agent "^(.*)$" \
"id:'900018', \
phase:1, \
t:none,t:sha1,t:hexEncode, \
setvar:tx.ua_hash=%{matched_var}, \
nolog, \
pass"
#SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" \
"id:'900019', \
phase:1, \
t:none, \
capture, \
setvar:tx.real_ip=%{tx.1}, \
nolog, \
pass"
#SecRule &TX:REAL_IP "!@eq 0" \
"id:'900020', \
phase:1, \
t:none, \
initcol:global=global, \
initcol:ip=%{tx.real_ip}_%{tx.ua_hash}, \
nolog, \
pass"
#SecRule &TX:REAL_IP "@eq 0" \
"id:'900021', \
phase:1, \
t:none, \
initcol:global=global, \
initcol:ip=%{remote_addr}_%{tx.ua_hash}, \
nolog, \
pass"

View file

@ -0,0 +1,2 @@
RewriteCond %{HTTP:Content-Disposition} \.php [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]

View file

@ -0,0 +1,247 @@
#ATTENTION!
#
#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,
#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED.
NameVirtualHost 192.168.100.218:80
NameVirtualHost 10.128.178.192:80
NameVirtualHost 192.168.100.218:443
NameVirtualHost 10.128.178.192:443
ServerName "254020-web1.example.com"
ServerAdmin "name@example.com"
DocumentRoot "/tmp"
<IfModule mod_logio.c>
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
</IfModule>
<IfModule !mod_logio.c>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
</IfModule>
TraceEnable off
ServerTokens ProductOnly
<Directory "/var/www/vhosts">
AllowOverride "All"
Options SymLinksIfOwnerMatch
Order allow,deny
Allow from all
<IfModule sapi_apache2.c>
php_admin_flag engine off
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine off
</IfModule>
</Directory>
<Directory "/usr/lib/mailman">
AllowOverride All
Options SymLinksIfOwnerMatch
Order allow,deny
Allow from all
<IfModule sapi_apache2.c>
php_admin_flag engine off
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine off
</IfModule>
</Directory>
<IfModule mod_headers.c>
Header add X-Powered-By PleskLin
</IfModule>
<IfModule mod_jk.c>
JkWorkersFile "/etc/httpd/conf/workers.properties"
JkLogFile /var/log/httpd/mod_jk.log
JkLogLevel info
</IfModule>
#Include "/etc/httpd/conf/plesk.conf.d/ip_default/*.conf"
<VirtualHost \
192.168.100.218:80 \
10.128.178.192:80 \
\
>
ServerName "default"
UseCanonicalName Off
DocumentRoot "/tmp"
ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
<IfModule mod_ssl.c>
SSLEngine off
</IfModule>
<Directory "/var/www/vhosts/default/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
<Directory /var/www/vhosts/default/htdocs>
<IfModule sapi_apache2.c>
php_admin_flag engine on
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
</IfModule>
</Directory>
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost \
192.168.100.218:443 \
\
>
ServerName "default-192_168_100_218"
UseCanonicalName Off
DocumentRoot "/tmp"
ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
SSLEngine on
SSLVerifyClient none
#SSLCertificateFile "/usr/local/psa/var/certificates/cert-9MgutN"
#SSLCACertificateFile "/usr/local/psa/var/certificates/cert-s6Wx3P"
<Directory "/var/www/vhosts/default/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
<Directory /var/www/vhosts/default/htdocs>
<IfModule sapi_apache2.c>
php_admin_flag engine on
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
</IfModule>
</Directory>
</VirtualHost>
<VirtualHost \
10.128.178.192:443 \
\
>
ServerName "default-10_128_178_192"
UseCanonicalName Off
DocumentRoot "/tmp"
ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin"
SSLEngine on
SSLVerifyClient none
#SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025"
<Directory "/var/www/vhosts/default/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
<Directory /var/www/vhosts/default/htdocs>
<IfModule sapi_apache2.c>
php_admin_flag engine on
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
</IfModule>
</Directory>
</VirtualHost>
</IfModule>
<VirtualHost \
192.168.100.218:80 \
10.128.178.192:80 \
\
>
DocumentRoot "/tmp"
ServerName lists
ServerAlias lists.*
UseCanonicalName Off
ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
Alias "/icons/" "/var/www/icons/"
Alias "/pipermail/" "/var/lib/mailman/archives/public/"
<IfModule mod_ssl.c>
SSLEngine off
</IfModule>
<Directory /var/lib/mailman/archives/>
Options FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost \
192.168.100.218:443 \
10.128.178.192:443 \
\
>
DocumentRoot "/tmp"
ServerName lists
ServerAlias lists.*
UseCanonicalName Off
ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
Alias "/icons/" "/var/www/icons/"
Alias "/pipermail/" "/var/lib/mailman/archives/public/"
SSLEngine on
SSLVerifyClient none
#SSLCertificateFile "/usr/local/psa/var/certificates/certxfb6025"
<Directory /var/lib/mailman/archives/>
Options FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
</IfModule>
<IfModule mod_rpaf.c>
RPAFproxy_ips 192.168.100.218 10.128.178.192
</IfModule>
<IfModule mod_rpaf-2.0.c>
RPAFproxy_ips 192.168.100.218 10.128.178.192
</IfModule>

View file

@ -1,13 +1,13 @@
"""Test for letsencrypt_apache.augeas_configurator."""
"""Test for certbot_apache.augeas_configurator."""
import os
import shutil
import unittest
import mock
from letsencrypt import errors
from certbot import errors
from letsencrypt_apache.tests import util
from certbot_apache.tests import util
class AugeasConfiguratorTest(util.ApacheTest):

View file

@ -1,11 +1,11 @@
"""Tests for letsencrypt_apache.parser."""
"""Tests for certbot_apache.parser."""
import os
import shutil
import unittest
from letsencrypt import errors
from certbot import errors
from letsencrypt_apache.tests import util
from certbot_apache.tests import util
class ComplexParserTest(util.ParserTest):
@ -88,7 +88,7 @@ class ComplexParserTest(util.ParserTest):
def verify_fnmatch(self, arg, hit=True):
"""Test if Include was correctly parsed."""
from letsencrypt_apache import parser
from certbot_apache import parser
self.parser.add_dir(parser.get_aug_path(self.parser.loc["default"]),
"Include", [arg])
if hit:

View file

@ -1,5 +1,5 @@
# pylint: disable=too-many-public-methods
"""Test for letsencrypt_apache.configurator."""
"""Test for certbot_apache.configurator."""
import os
import shutil
import socket
@ -9,15 +9,16 @@ import mock
from acme import challenges
from letsencrypt import achallenges
from letsencrypt import errors
from certbot import achallenges
from certbot import errors
from letsencrypt.tests import acme_util
from certbot.tests import acme_util
from letsencrypt_apache import configurator
from letsencrypt_apache import obj
from certbot_apache import configurator
from certbot_apache import parser
from certbot_apache import obj
from letsencrypt_apache.tests import util
from certbot_apache.tests import util
class MultipleVhostsTest(util.ApacheTest):
@ -38,7 +39,7 @@ class MultipleVhostsTest(util.ApacheTest):
def mocked_deploy_cert(*args, **kwargs):
"""a helper to mock a deployed cert"""
with mock.patch("letsencrypt_apache.configurator.ApacheConfigurator.enable_mod"):
with mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod"):
config.real_deploy_cert(*args, **kwargs)
self.config.deploy_cert = mocked_deploy_cert
return self.config
@ -48,14 +49,24 @@ class MultipleVhostsTest(util.ApacheTest):
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
@mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
@mock.patch("certbot_apache.configurator.util.exe_exists")
def test_prepare_no_install(self, mock_exe_exists):
mock_exe_exists.return_value = False
self.assertRaises(
errors.NoInstallationError, self.config.prepare)
@mock.patch("letsencrypt_apache.parser.ApacheParser")
@mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
@mock.patch("certbot_apache.augeas_configurator.AugeasConfigurator.init_augeas")
def test_prepare_no_augeas(self, mock_init_augeas):
""" Test augeas initialization ImportError """
def side_effect_error():
""" Side effect error for the test """
raise ImportError
mock_init_augeas.side_effect = side_effect_error
self.assertRaises(
errors.NoInstallationError, self.config.prepare)
@mock.patch("certbot_apache.parser.ApacheParser")
@mock.patch("certbot_apache.configurator.util.exe_exists")
def test_prepare_version(self, mock_exe_exists, _):
mock_exe_exists.return_value = True
self.config.version = None
@ -65,8 +76,8 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertRaises(
errors.NotSupportedError, self.config.prepare)
@mock.patch("letsencrypt_apache.parser.ApacheParser")
@mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
@mock.patch("certbot_apache.parser.ApacheParser")
@mock.patch("certbot_apache.configurator.util.exe_exists")
def test_prepare_old_aug(self, mock_exe_exists, _):
mock_exe_exists.return_value = True
self.config.config_test = mock.Mock()
@ -76,7 +87,7 @@ class MultipleVhostsTest(util.ApacheTest):
errors.NotSupportedError, self.config.prepare)
def test_add_parser_arguments(self): # pylint: disable=no-self-use
from letsencrypt_apache.configurator import ApacheConfigurator
from certbot_apache.configurator import ApacheConfigurator
# Weak test..
ApacheConfigurator.add_parser_arguments(mock.MagicMock())
@ -85,10 +96,11 @@ class MultipleVhostsTest(util.ApacheTest):
mock_getutility.notification = mock.MagicMock(return_value=True)
names = self.config.get_all_names()
self.assertEqual(names, set(
["letsencrypt.demo", "encryption-example.demo", "ip-172-30-0-17", "*.blue.purple.com"]))
["certbot.demo", "ocspvhost.com", "encryption-example.demo",
"ip-172-30-0-17", "*.blue.purple.com"]))
@mock.patch("zope.component.getUtility")
@mock.patch("letsencrypt_apache.configurator.socket.gethostbyaddr")
@mock.patch("certbot_apache.configurator.socket.gethostbyaddr")
def test_get_all_names_addrs(self, mock_gethost, mock_getutility):
mock_gethost.side_effect = [("google.com", "", ""), socket.error]
notification = mock.Mock()
@ -100,13 +112,23 @@ class MultipleVhostsTest(util.ApacheTest):
obj.Addr(("zombo.com",)),
obj.Addr(("192.168.1.2"))]),
True, False)
self.config.vhosts.append(vhost)
names = self.config.get_all_names()
self.assertEqual(len(names), 6)
self.assertEqual(len(names), 7)
self.assertTrue("zombo.com" in names)
self.assertTrue("google.com" in names)
self.assertTrue("letsencrypt.demo" in names)
self.assertTrue("certbot.demo" in names)
def test_bad_servername_alias(self):
ssl_vh1 = obj.VirtualHost(
"fp1", "ap1", set([obj.Addr(("*", "443"))]),
True, False)
# pylint: disable=protected-access
self.config._add_servernames(ssl_vh1)
self.assertTrue(
self.config._add_servername_alias("oy_vey", ssl_vh1) is None)
def test_add_servernames_alias(self):
self.config.parser.add_dir(
@ -124,7 +146,7 @@ class MultipleVhostsTest(util.ApacheTest):
"""
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 7)
self.assertEqual(len(vhs), 8)
found = 0
for vhost in vhs:
@ -135,29 +157,29 @@ class MultipleVhostsTest(util.ApacheTest):
else:
raise Exception("Missed: %s" % vhost) # pragma: no cover
self.assertEqual(found, 7)
self.assertEqual(found, 8)
# Handle case of non-debian layout get_virtual_hosts
with mock.patch(
"letsencrypt_apache.configurator.ApacheConfigurator.conf"
"certbot_apache.configurator.ApacheConfigurator.conf"
) as mock_conf:
mock_conf.return_value = False
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 7)
self.assertEqual(len(vhs), 8)
@mock.patch("letsencrypt_apache.display_ops.select_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_none_avail(self, mock_select):
mock_select.return_value = None
self.assertRaises(
errors.PluginError, self.config.choose_vhost, "none.com")
@mock.patch("letsencrypt_apache.display_ops.select_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_select_vhost_ssl(self, mock_select):
mock_select.return_value = self.vh_truth[1]
self.assertEqual(
self.vh_truth[1], self.config.choose_vhost("none.com"))
@mock.patch("letsencrypt_apache.display_ops.select_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_select_vhost_non_ssl(self, mock_select):
mock_select.return_value = self.vh_truth[0]
chosen_vhost = self.config.choose_vhost("none.com")
@ -169,13 +191,13 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertFalse(self.vh_truth[0].ssl)
self.assertTrue(chosen_vhost.ssl)
@mock.patch("letsencrypt_apache.display_ops.select_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_select_vhost_with_temp(self, mock_select):
mock_select.return_value = self.vh_truth[0]
chosen_vhost = self.config.choose_vhost("none.com", temp=True)
self.assertEqual(self.vh_truth[0], chosen_vhost)
@mock.patch("letsencrypt_apache.display_ops.select_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
def test_choose_vhost_select_vhost_conflicting_non_ssl(self, mock_select):
mock_select.return_value = self.vh_truth[3]
conflicting_vhost = obj.VirtualHost(
@ -203,7 +225,7 @@ class MultipleVhostsTest(util.ApacheTest):
def test_find_best_vhost(self):
# pylint: disable=protected-access
self.assertEqual(
self.vh_truth[3], self.config._find_best_vhost("letsencrypt.demo"))
self.vh_truth[3], self.config._find_best_vhost("certbot.demo"))
self.assertEqual(
self.vh_truth[0],
self.config._find_best_vhost("encryption-example.demo"))
@ -224,16 +246,18 @@ class MultipleVhostsTest(util.ApacheTest):
# Assume only the two default vhosts.
self.config.vhosts = [
vh for vh in self.config.vhosts
if vh.name not in ["letsencrypt.demo", "encryption-example.demo"]
if vh.name not in ["certbot.demo",
"encryption-example.demo",
"ocspvhost.com"]
and "*.blue.purple.com" not in vh.aliases
]
self.assertEqual(
self.config._find_best_vhost("example.demo"), self.vh_truth[2])
self.config._find_best_vhost("encryption-example.demo"),
self.vh_truth[2])
def test_non_default_vhosts(self):
# pylint: disable=protected-access
self.assertEqual(len(self.config._non_default_vhosts()), 5)
self.assertEqual(len(self.config._non_default_vhosts()), 6)
def test_is_site_enabled(self):
"""Test if site is enabled.
@ -254,9 +278,9 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.is_site_enabled,
"irrelevant")
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("letsencrypt_apache.parser.subprocess.Popen")
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
@mock.patch("certbot_apache.parser.subprocess.Popen")
def test_enable_mod(self, mock_popen, mock_exe_exists, mock_run_script):
mock_popen().communicate.return_value = ("Define: DUMP_RUN_CFG", "")
mock_popen().returncode = 0
@ -273,7 +297,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertRaises(
errors.NotSupportedError, self.config.enable_mod, "ssl")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("certbot.util.exe_exists")
def test_enable_mod_no_disable(self, mock_exe_exists):
mock_exe_exists.return_value = False
self.assertRaises(
@ -539,7 +563,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertEqual(self.config.is_name_vhost(self.vh_truth[0]),
self.config.is_name_vhost(ssl_vhost))
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_clean_vhost_ssl(self):
# pylint: disable=protected-access
@ -636,8 +660,8 @@ class MultipleVhostsTest(util.ApacheTest):
self.config._add_name_vhost_if_necessary(self.vh_truth[0])
self.assertEqual(self.config.save.call_count, 2)
@mock.patch("letsencrypt_apache.configurator.tls_sni_01.ApacheTlsSni01.perform")
@mock.patch("letsencrypt_apache.configurator.ApacheConfigurator.restart")
@mock.patch("certbot_apache.configurator.tls_sni_01.ApacheTlsSni01.perform")
@mock.patch("certbot_apache.configurator.ApacheConfigurator.restart")
def test_perform(self, mock_restart, mock_perform):
# Only tests functionality specific to configurator.perform
# Note: As more challenges are offered this will have to be expanded
@ -656,7 +680,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertEqual(mock_restart.call_count, 1)
@mock.patch("letsencrypt_apache.configurator.ApacheConfigurator.restart")
@mock.patch("certbot_apache.configurator.ApacheConfigurator.restart")
def test_cleanup(self, mock_restart):
_, achall1, achall2 = self.get_achalls()
@ -669,7 +693,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.cleanup([achall2])
self.assertTrue(mock_restart.called)
@mock.patch("letsencrypt_apache.configurator.ApacheConfigurator.restart")
@mock.patch("certbot_apache.configurator.ApacheConfigurator.restart")
def test_cleanup_no_errors(self, mock_restart):
_, achall1, achall2 = self.get_achalls()
@ -681,7 +705,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.cleanup([achall1, achall2])
self.assertTrue(mock_restart.called)
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("certbot.util.run_script")
def test_get_version(self, mock_script):
mock_script.return_value = (
"Server Version: Apache/2.4.2 (Debian)", "")
@ -703,21 +727,21 @@ class MultipleVhostsTest(util.ApacheTest):
mock_script.side_effect = errors.SubprocessError("Can't find program")
self.assertRaises(errors.PluginError, self.config.get_version)
@mock.patch("letsencrypt_apache.configurator.le_util.run_script")
@mock.patch("certbot_apache.configurator.util.run_script")
def test_restart(self, _):
self.config.restart()
@mock.patch("letsencrypt_apache.configurator.le_util.run_script")
@mock.patch("certbot_apache.configurator.util.run_script")
def test_restart_bad_process(self, mock_run_script):
mock_run_script.side_effect = [None, errors.SubprocessError]
self.assertRaises(errors.MisconfigurationError, self.config.restart)
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("certbot.util.run_script")
def test_config_test(self, _):
self.config.config_test()
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("certbot.util.run_script")
def test_config_test_bad_process(self, mock_run_script):
mock_run_script.side_effect = errors.SubprocessError
@ -726,16 +750,15 @@ class MultipleVhostsTest(util.ApacheTest):
def test_get_all_certs_keys(self):
c_k = self.config.get_all_certs_keys()
self.assertEqual(len(c_k), 2)
self.assertEqual(len(c_k), 3)
cert, key, path = next(iter(c_k))
self.assertTrue("cert" in cert)
self.assertTrue("key" in key)
self.assertTrue("default-ssl" in path)
self.assertTrue("default-ssl" in path or "ocsp-ssl" in path)
def test_get_all_certs_keys_malformed_conf(self):
self.config.parser.find_dir = mock.Mock(
side_effect=[["path"], [], ["path"], []])
side_effect=[["path"], [], ["path"], [], ["path"], []])
c_k = self.config.get_all_certs_keys()
self.assertFalse(c_k)
@ -747,7 +770,7 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue(isinstance(self.config.get_chall_pref(""), list))
def test_install_ssl_options_conf(self):
from letsencrypt_apache.configurator import install_ssl_options_conf
from certbot_apache.configurator import install_ssl_options_conf
path = os.path.join(self.work_dir, "test_it")
install_ssl_options_conf(path)
self.assertTrue(os.path.isfile(path))
@ -756,15 +779,20 @@ class MultipleVhostsTest(util.ApacheTest):
def test_supported_enhancements(self):
self.assertTrue(isinstance(self.config.supported_enhancements(), list))
@mock.patch("letsencrypt.le_util.exe_exists")
def test_enhance_unknown_vhost(self, mock_exe):
@mock.patch("certbot_apache.configurator.ApacheConfigurator._get_http_vhost")
@mock.patch("certbot_apache.display_ops.select_vhost")
@mock.patch("certbot.util.exe_exists")
def test_enhance_unknown_vhost(self, mock_exe, mock_sel_vhost, mock_get):
self.config.parser.modules.add("rewrite_module")
mock_exe.return_value = True
ssl_vh = obj.VirtualHost(
"fp", "ap", set([obj.Addr(("*", "443"))]),
ssl_vh1 = obj.VirtualHost(
"fp1", "ap1", set([obj.Addr(("*", "443"))]),
True, False)
ssl_vh.name = "satoshi.com"
self.config.vhosts.append(ssl_vh)
ssl_vh1.name = "satoshi.com"
self.config.vhosts.append(ssl_vh1)
mock_sel_vhost.return_value = None
mock_get.return_value = None
self.assertRaises(
errors.PluginError,
self.config.enhance, "satoshi.com", "redirect")
@ -772,23 +800,102 @@ class MultipleVhostsTest(util.ApacheTest):
def test_enhance_unknown_enhancement(self):
self.assertRaises(
errors.PluginError,
self.config.enhance, "letsencrypt.demo", "unknown_enhancement")
self.config.enhance, "certbot.demo", "unknown_enhancement")
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_ocsp_stapling(self, mock_exe, mock_run_script):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "staple-ocsp")
self.assertTrue("socache_shmcb_module" in self.config.parser.modules)
self.assertTrue(mock_run_script.called)
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
ssl_use_stapling_aug_path = self.config.parser.find_dir(
"SSLUseStapling", "on", ssl_vhost.path)
self.assertEqual(len(ssl_use_stapling_aug_path), 1)
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
"shmcb:/var/run/apache2/stapling_cache(128000)",
ssl_vhost_aug_path)
self.assertEqual(len(stapling_cache_aug_path), 1)
@mock.patch("certbot.util.exe_exists")
def test_ocsp_stapling_twice(self, mock_exe):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("socache_shmcb_module")
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
mock_exe.return_value = True
# Checking the case with already enabled ocsp stapling configuration
self.config.enhance("ocspvhost.com", "staple-ocsp")
# Get the ssl vhost for letsencrypt.demo
ssl_vhost = self.config.assoc["ocspvhost.com"]
ssl_use_stapling_aug_path = self.config.parser.find_dir(
"SSLUseStapling", "on", ssl_vhost.path)
self.assertEqual(len(ssl_use_stapling_aug_path), 1)
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
"shmcb:/var/run/apache2/stapling_cache(128000)",
ssl_vhost_aug_path)
self.assertEqual(len(stapling_cache_aug_path), 1)
@mock.patch("certbot.util.exe_exists")
def test_ocsp_unsupported_apache_version(self, mock_exe):
mock_exe.return_value = True
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
self.config.parser.modules.add("socache_shmcb_module")
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
self.assertRaises(errors.PluginError,
self.config.enhance, "certbot.demo", "staple-ocsp")
def test_get_http_vhost_third_filter(self):
ssl_vh = obj.VirtualHost(
"fp", "ap", set([obj.Addr(("*", "443"))]),
True, False)
ssl_vh.name = "satoshi.com"
self.config.vhosts.append(ssl_vh)
# pylint: disable=protected-access
http_vh = self.config._get_http_vhost(ssl_vh)
self.assertTrue(http_vh.ssl == False)
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_http_header_hsts(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
mock_exe.return_value = True
# This will create an ssl vhost for letsencrypt.demo
self.config.enhance("letsencrypt.demo", "ensure-http-header",
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "ensure-http-header",
"Strict-Transport-Security")
self.assertTrue("headers_module" in self.config.parser.modules)
# Get the ssl vhost for letsencrypt.demo
ssl_vhost = self.config.assoc["letsencrypt.demo"]
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
# These are not immediately available in find_dir even with save() and
# load(). They must be found in sites-available
@ -803,7 +910,7 @@ class MultipleVhostsTest(util.ApacheTest):
# skip the enable mod
self.config.parser.modules.add("headers_module")
# This will create an ssl vhost for letsencrypt.demo
# This will create an ssl vhost for certbot.demo
self.config.enhance("encryption-example.demo", "ensure-http-header",
"Strict-Transport-Security")
@ -812,21 +919,21 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.enhance, "encryption-example.demo",
"ensure-http-header", "Strict-Transport-Security")
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_http_header_uir(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
mock_exe.return_value = True
# This will create an ssl vhost for letsencrypt.demo
self.config.enhance("letsencrypt.demo", "ensure-http-header",
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "ensure-http-header",
"Upgrade-Insecure-Requests")
self.assertTrue("headers_module" in self.config.parser.modules)
# Get the ssl vhost for letsencrypt.demo
ssl_vhost = self.config.assoc["letsencrypt.demo"]
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
# These are not immediately available in find_dir even with save() and
# load(). They must be found in sites-available
@ -841,7 +948,7 @@ class MultipleVhostsTest(util.ApacheTest):
# skip the enable mod
self.config.parser.modules.add("headers_module")
# This will create an ssl vhost for letsencrypt.demo
# This will create an ssl vhost for certbot.demo
self.config.enhance("encryption-example.demo", "ensure-http-header",
"Upgrade-Insecure-Requests")
@ -850,15 +957,15 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.enhance, "encryption-example.demo",
"ensure-http-header", "Upgrade-Insecure-Requests")
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_redirect_well_formed_http(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2))
# This will create an ssl vhost for letsencrypt.demo
self.config.enhance("letsencrypt.demo", "redirect")
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "redirect")
# These are not immediately available in find_dir even with save() and
# load(). They must be found in sites-available
@ -894,12 +1001,12 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.assertTrue(self.config._is_rewrite_engine_on(self.vh_truth[3]))
@mock.patch("letsencrypt.le_util.run_script")
@mock.patch("letsencrypt.le_util.exe_exists")
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_redirect_with_existing_rewrite(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2))
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
# Create a preexisting rewrite rule
self.config.parser.add_dir(
@ -907,8 +1014,8 @@ class MultipleVhostsTest(util.ApacheTest):
"UnknownTarget"])
self.config.save()
# This will create an ssl vhost for letsencrypt.demo
self.config.enhance("letsencrypt.demo", "redirect")
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "redirect")
# These are not immediately available in find_dir even with save() and
# load(). They must be found in sites-available
@ -938,15 +1045,31 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertRaises(
errors.PluginError, self.config._enable_redirect, ssl_vh, "")
def test_redirect_twice(self):
def test_redirect_two_domains_one_vhost(self):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
self.config.enhance("encryption-example.demo", "redirect")
self.config.enhance("red.blue.purple.com", "redirect")
verify_no_redirect = ("certbot_apache.configurator."
"ApacheConfigurator._verify_no_certbot_redirect")
with mock.patch(verify_no_redirect) as mock_verify:
self.config.enhance("green.blue.purple.com", "redirect")
self.assertFalse(mock_verify.called)
def test_redirect_from_previous_run(self):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
self.config.enhance("red.blue.purple.com", "redirect")
# Clear state about enabling redirect on this run
# pylint: disable=protected-access
self.config._enhanced_vhosts["redirect"].clear()
self.assertRaises(
errors.PluginEnhancementAlreadyPresent,
self.config.enhance, "encryption-example.demo", "redirect")
self.config.enhance, "green.blue.purple.com", "redirect")
def test_create_own_redirect(self):
self.config.parser.modules.add("rewrite_module")
@ -957,7 +1080,7 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.config._enable_redirect(self.vh_truth[1], "")
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_create_own_redirect_for_old_apache_version(self):
self.config.parser.modules.add("rewrite_module")
@ -968,7 +1091,7 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.config._enable_redirect(self.vh_truth[1], "")
self.assertEqual(len(self.config.vhosts), 8)
self.assertEqual(len(self.config.vhosts), 9)
def test_sift_line(self):
# pylint: disable=protected-access
@ -981,7 +1104,7 @@ class MultipleVhostsTest(util.ApacheTest):
normal_target = "RewriteRule ^/(.*) http://www.a.com:1234/$1 [L,R]"
self.assertFalse(self.config._sift_line(normal_target))
@mock.patch("letsencrypt_apache.configurator.zope.component.getUtility")
@mock.patch("certbot_apache.configurator.zope.component.getUtility")
def test_make_vhost_ssl_with_existing_rewrite_rule(self, mock_get_utility):
self.config.parser.modules.add("rewrite_module")
@ -1024,7 +1147,7 @@ class MultipleVhostsTest(util.ApacheTest):
challenges.TLSSNI01(
token="uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"),
"pending"),
domain="letsencrypt.demo", account_key=account_key)
domain="certbot.demo", account_key=account_key)
return account_key, achall1, achall2

View file

@ -1,26 +1,26 @@
"""Test for letsencrypt_apache.configurator."""
"""Test for certbot_apache.configurator."""
import mock
import unittest
from letsencrypt_apache import constants
from certbot_apache import constants
class ConstantsTest(unittest.TestCase):
@mock.patch("letsencrypt.le_util.get_os_info")
@mock.patch("certbot.util.get_os_info")
def test_get_debian_value(self, os_info):
os_info.return_value = ('Debian', '', '')
self.assertEqual(constants.os_constant("vhost_root"),
"/etc/apache2/sites-available")
@mock.patch("letsencrypt.le_util.get_os_info")
@mock.patch("certbot.util.get_os_info")
def test_get_centos_value(self, os_info):
os_info.return_value = ('CentOS Linux', '', '')
self.assertEqual(constants.os_constant("vhost_root"),
"/etc/httpd/conf.d")
@mock.patch("letsencrypt.le_util.get_os_info")
@mock.patch("certbot.util.get_os_info")
def test_get_default_value(self, os_info):
os_info.return_value = ('Nonexistent Linux', '', '')
self.assertEqual(constants.os_constant("vhost_root"),

View file

@ -1,20 +1,20 @@
"""Test letsencrypt_apache.display_ops."""
"""Test certbot_apache.display_ops."""
import sys
import unittest
import mock
import zope.component
from letsencrypt.display import util as display_util
from letsencrypt import errors
from certbot.display import util as display_util
from certbot import errors
from letsencrypt_apache import obj
from certbot_apache import obj
from letsencrypt_apache.tests import util
from certbot_apache.tests import util
class SelectVhostTest(unittest.TestCase):
"""Tests for letsencrypt_apache.display_ops.select_vhost."""
"""Tests for certbot_apache.display_ops.select_vhost."""
def setUp(self):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
@ -24,15 +24,15 @@ class SelectVhostTest(unittest.TestCase):
@classmethod
def _call(cls, vhosts):
from letsencrypt_apache.display_ops import select_vhost
from certbot_apache.display_ops import select_vhost
return select_vhost("example.com", vhosts)
@mock.patch("letsencrypt_apache.display_ops.zope.component.getUtility")
@mock.patch("certbot_apache.display_ops.zope.component.getUtility")
def test_successful_choice(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 3)
self.assertEqual(self.vhosts[3], self._call(self.vhosts))
@mock.patch("letsencrypt_apache.display_ops.zope.component.getUtility")
@mock.patch("certbot_apache.display_ops.zope.component.getUtility")
def test_noninteractive(self, mock_util):
mock_util().menu.side_effect = errors.MissingCommandlineFlag("no vhost default")
try:
@ -40,7 +40,7 @@ class SelectVhostTest(unittest.TestCase):
except errors.MissingCommandlineFlag as e:
self.assertTrue("VirtualHost directives" in e.message)
@mock.patch("letsencrypt_apache.display_ops.zope.component.getUtility")
@mock.patch("certbot_apache.display_ops.zope.component.getUtility")
def test_more_info_cancel(self, mock_util):
mock_util().menu.side_effect = [
(display_util.HELP, 1),
@ -54,9 +54,9 @@ class SelectVhostTest(unittest.TestCase):
def test_no_vhosts(self):
self.assertEqual(self._call([]), None)
@mock.patch("letsencrypt_apache.display_ops.display_util")
@mock.patch("letsencrypt_apache.display_ops.zope.component.getUtility")
@mock.patch("letsencrypt_apache.display_ops.logger")
@mock.patch("certbot_apache.display_ops.display_util")
@mock.patch("certbot_apache.display_ops.zope.component.getUtility")
@mock.patch("certbot_apache.display_ops.logger")
def test_small_display(self, mock_logger, mock_util, mock_display_util):
mock_display_util.WIDTH = 20
mock_util().menu.return_value = (display_util.OK, 0)
@ -64,7 +64,7 @@ class SelectVhostTest(unittest.TestCase):
self.assertEqual(mock_logger.debug.call_count, 1)
@mock.patch("letsencrypt_apache.display_ops.zope.component.getUtility")
@mock.patch("certbot_apache.display_ops.zope.component.getUtility")
def test_multiple_names(self, mock_util):
mock_util().menu.return_value = (display_util.OK, 5)

View file

@ -1,4 +1,4 @@
"""Tests for letsencrypt_apache.obj."""
"""Tests for certbot_apache.obj."""
import unittest
@ -6,8 +6,8 @@ class VirtualHostTest(unittest.TestCase):
"""Test the VirtualHost class."""
def setUp(self):
from letsencrypt_apache.obj import Addr
from letsencrypt_apache.obj import VirtualHost
from certbot_apache.obj import Addr
from certbot_apache.obj import VirtualHost
self.addr1 = Addr.fromstring("127.0.0.1")
self.addr2 = Addr.fromstring("127.0.0.1:443")
@ -33,8 +33,8 @@ class VirtualHostTest(unittest.TestCase):
self.assertFalse(self.vhost1 != self.vhost1b)
def test_conflicts(self):
from letsencrypt_apache.obj import Addr
from letsencrypt_apache.obj import VirtualHost
from certbot_apache.obj import Addr
from certbot_apache.obj import VirtualHost
complex_vh = VirtualHost(
"fp", "vhp",
@ -51,7 +51,7 @@ class VirtualHostTest(unittest.TestCase):
self.addr_default]))
def test_same_server(self):
from letsencrypt_apache.obj import VirtualHost
from certbot_apache.obj import VirtualHost
no_name1 = VirtualHost(
"fp", "vhp", set([self.addr1]), False, False, None)
no_name2 = VirtualHost(
@ -74,7 +74,7 @@ class VirtualHostTest(unittest.TestCase):
class AddrTest(unittest.TestCase):
"""Test obj.Addr."""
def setUp(self):
from letsencrypt_apache.obj import Addr
from certbot_apache.obj import Addr
self.addr = Addr.fromstring("*:443")
self.addr1 = Addr.fromstring("127.0.0.1")
@ -89,7 +89,7 @@ class AddrTest(unittest.TestCase):
self.assertTrue(self.addr2.is_wildcard())
def test_get_sni_addr(self):
from letsencrypt_apache.obj import Addr
from certbot_apache.obj import Addr
self.assertEqual(
self.addr.get_sni_addr("443"), Addr.fromstring("*:443"))
self.assertEqual(

View file

@ -1,4 +1,4 @@
"""Tests for letsencrypt_apache.parser."""
"""Tests for certbot_apache.parser."""
import os
import shutil
import unittest
@ -6,9 +6,9 @@ import unittest
import augeas
import mock
from letsencrypt import errors
from certbot import errors
from letsencrypt_apache.tests import util
from certbot_apache.tests import util
class BasicParserTest(util.ParserTest):
@ -31,12 +31,12 @@ class BasicParserTest(util.ParserTest):
def test_parse_file(self):
"""Test parse_file.
letsencrypt.conf is chosen as the test file as it will not be
certbot.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, "not-parsed-by-default", "letsencrypt.conf")
self.config_path, "not-parsed-by-default", "certbot.conf")
self.parser._parse_file(file_path) # pylint: disable=protected-access
@ -72,7 +72,7 @@ class BasicParserTest(util.ParserTest):
Path must be valid before attempting to add to augeas
"""
from letsencrypt_apache.parser import get_aug_path
from certbot_apache.parser import get_aug_path
# This makes sure that find_dir will work
self.parser.modules.add("mod_ssl.c")
@ -86,7 +86,7 @@ class BasicParserTest(util.ParserTest):
self.assertTrue("IfModule" in matches[0])
def test_add_dir_to_ifmodssl_multiple(self):
from letsencrypt_apache.parser import get_aug_path
from certbot_apache.parser import get_aug_path
# This makes sure that find_dir will work
self.parser.modules.add("mod_ssl.c")
@ -100,11 +100,11 @@ class BasicParserTest(util.ParserTest):
self.assertTrue("IfModule" in matches[0])
def test_get_aug_path(self):
from letsencrypt_apache.parser import get_aug_path
from certbot_apache.parser import get_aug_path
self.assertEqual("/files/etc/apache", get_aug_path("/etc/apache"))
def test_set_locations(self):
with mock.patch("letsencrypt_apache.parser.os.path") as mock_path:
with mock.patch("certbot_apache.parser.os.path") as mock_path:
mock_path.isfile.side_effect = [False, False]
@ -114,7 +114,7 @@ class BasicParserTest(util.ParserTest):
self.assertEqual(results["default"], results["listen"])
self.assertEqual(results["default"], results["name"])
@mock.patch("letsencrypt_apache.parser.ApacheParser._get_runtime_cfg")
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
def test_update_runtime_variables(self, mock_cfg):
mock_cfg.return_value = (
'ServerRoot: "/etc/apache2"\n'
@ -139,7 +139,7 @@ class BasicParserTest(util.ParserTest):
self.parser.update_runtime_variables()
self.assertEqual(self.parser.variables, expected_vars)
@mock.patch("letsencrypt_apache.parser.ApacheParser._get_runtime_cfg")
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
def test_update_runtime_vars_bad_output(self, mock_cfg):
mock_cfg.return_value = "Define: TLS=443=24"
self.parser.update_runtime_variables()
@ -148,8 +148,8 @@ class BasicParserTest(util.ParserTest):
self.assertRaises(
errors.PluginError, self.parser.update_runtime_variables)
@mock.patch("letsencrypt_apache.constants.os_constant")
@mock.patch("letsencrypt_apache.parser.subprocess.Popen")
@mock.patch("certbot_apache.constants.os_constant")
@mock.patch("certbot_apache.parser.subprocess.Popen")
def test_update_runtime_vars_bad_ctl(self, mock_popen, mock_const):
mock_popen.side_effect = OSError
mock_const.return_value = "nonexistent"
@ -157,7 +157,7 @@ class BasicParserTest(util.ParserTest):
errors.MisconfigurationError,
self.parser.update_runtime_variables)
@mock.patch("letsencrypt_apache.parser.subprocess.Popen")
@mock.patch("certbot_apache.parser.subprocess.Popen")
def test_update_runtime_vars_bad_exit(self, mock_popen):
mock_popen().communicate.return_value = ("", "")
mock_popen.returncode = -1
@ -177,9 +177,9 @@ class ParserInitTest(util.ApacheTest):
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
@mock.patch("letsencrypt_apache.parser.ApacheParser._get_runtime_cfg")
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
def test_unparsable(self, mock_cfg):
from letsencrypt_apache.parser import ApacheParser
from certbot_apache.parser import ApacheParser
mock_cfg.return_value = ('Define: TEST')
self.assertRaises(
errors.PluginError,
@ -187,9 +187,9 @@ class ParserInitTest(util.ApacheTest):
"/dummy/vhostpath", version=(2, 2, 22))
def test_root_normalized(self):
from letsencrypt_apache.parser import ApacheParser
from certbot_apache.parser import ApacheParser
with mock.patch("letsencrypt_apache.parser.ApacheParser."
with mock.patch("certbot_apache.parser.ApacheParser."
"update_runtime_variables"):
path = os.path.join(
self.temp_dir,
@ -201,8 +201,8 @@ class ParserInitTest(util.ApacheTest):
self.assertEqual(parser.root, self.config_path)
def test_root_absolute(self):
from letsencrypt_apache.parser import ApacheParser
with mock.patch("letsencrypt_apache.parser.ApacheParser."
from certbot_apache.parser import ApacheParser
with mock.patch("certbot_apache.parser.ApacheParser."
"update_runtime_variables"):
parser = ApacheParser(
self.aug, os.path.relpath(self.config_path),
@ -211,8 +211,8 @@ class ParserInitTest(util.ApacheTest):
self.assertEqual(parser.root, self.config_path)
def test_root_no_trailing_slash(self):
from letsencrypt_apache.parser import ApacheParser
with mock.patch("letsencrypt_apache.parser.ApacheParser."
from certbot_apache.parser import ApacheParser
with mock.patch("certbot_apache.parser.ApacheParser."
"update_runtime_variables"):
parser = ApacheParser(
self.aug, self.config_path + os.path.sep,

View file

@ -1,5 +1,5 @@
<VirtualHost *:80>
# How well does Let's Encrypt work without a ServerName/Alias?
# How well does Certbot work without a ServerName/Alias?
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

View file

@ -16,8 +16,8 @@
# /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
SSLCertificateFile /etc/apache2/certs/certbot-cert_5.pem
SSLCertificateKeyFile /etc/apache2/ssl/key-certbot_15.pem
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars

Some files were not shown because too many files have changed in this diff Show more