mirror of
https://github.com/certbot/certbot.git
synced 2026-06-03 13:59:02 -04:00
Merge remote-tracking branch 'origin/master' into dialog-escape
This commit is contained in:
commit
e231dae2c1
493 changed files with 8408 additions and 4800 deletions
3
.coveragerc
Normal file
3
.coveragerc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[report]
|
||||
# show lines missing coverage in output
|
||||
show_missing = True
|
||||
11
.gitattributes
vendored
11
.gitattributes
vendored
|
|
@ -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
1
.gitignore
vendored
|
|
@ -8,6 +8,7 @@ dist*/
|
|||
/.tox/
|
||||
/releases/
|
||||
letsencrypt.log
|
||||
certbot.log
|
||||
letsencrypt-auto-source/letsencrypt-auto.sig.lzma.base64
|
||||
|
||||
# coverage
|
||||
|
|
|
|||
46
.travis.yml
46
.travis.yml
|
|
@ -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)'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
39
Dockerfile
39
Dockerfile
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Let's Encrypt Python Client
|
||||
Certbot ACME Client
|
||||
Copyright (c) Electronic Frontier Foundation and others
|
||||
Licensed Apache Version 2.0
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
105
README.rst
105
README.rst
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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=[
|
||||
|
|
|
|||
7
certbot-apache/MANIFEST.in
Normal file
7
certbot-apache/MANIFEST.in
Normal 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
|
||||
1
certbot-apache/README.rst
Normal file
1
certbot-apache/README.rst
Normal file
|
|
@ -0,0 +1 @@
|
|||
Apache plugin for Certbot
|
||||
1
certbot-apache/certbot_apache/__init__.py
Normal file
1
certbot-apache/certbot_apache/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""Certbot Apache plugin."""
|
||||
|
|
@ -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):
|
||||
2
certbot-apache/certbot_apache/augeas_lens/README
Normal file
2
certbot-apache/certbot_apache/augeas_lens/README
Normal 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
|
||||
|
|
@ -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 = /\\\\./
|
||||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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):
|
||||
|
|
@ -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__)
|
||||
|
||||
1
certbot-apache/certbot_apache/tests/__init__.py
Normal file
1
certbot-apache/certbot_apache/tests/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""Certbot Apache Tests"""
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
RewriteCond %{HTTP:Content-Disposition} \.php [NC]
|
||||
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]
|
||||
|
|
@ -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>
|
||||
|
|
@ -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):
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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"),
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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(
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
Loading…
Reference in a new issue