Compare commits
130 Commits
test-apach
...
test-fix-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a8663b778 | ||
|
|
4c914eef01 | ||
|
|
b1f2d89c1c | ||
|
|
6dfbb71d15 | ||
|
|
a775ce3ac1 | ||
|
|
c7b9288249 | ||
|
|
b84edfd39a | ||
|
|
88d9a31cf9 | ||
|
|
1dff022d05 | ||
|
|
2b4c2a7f55 | ||
|
|
baf43a2dbc | ||
|
|
ebce0adb5a | ||
|
|
61f77c35c0 | ||
|
|
1b76faada6 | ||
|
|
b79bcd0bf2 | ||
|
|
5f6ab47a7b | ||
|
|
d87c905c06 | ||
|
|
9b848b1d65 | ||
|
|
f555e4bf1f | ||
|
|
0de2645a8f | ||
|
|
fcecdfbcc5 | ||
|
|
73cd5aa81c | ||
|
|
3d9d212040 | ||
|
|
78deca4f60 | ||
|
|
3c24ff88cc | ||
|
|
08d91b456b | ||
|
|
1c05b9bd07 | ||
|
|
fffa74edb2 | ||
|
|
8956de6bee | ||
|
|
9bc4286a27 | ||
|
|
3e848b8fce | ||
|
|
fb1aafb5d2 | ||
|
|
f8ff881d23 | ||
|
|
ef3f8888b5 | ||
|
|
a45efcd40d | ||
|
|
63d673a3e0 | ||
|
|
9796128fee | ||
|
|
de6b56bec0 | ||
|
|
6f711d9ae8 | ||
|
|
6fcdfb0e50 | ||
|
|
e19b2e04c7 | ||
|
|
2dbe47f3a7 | ||
|
|
0f31d9b7ac | ||
|
|
60673e8a81 | ||
|
|
3132c32c26 | ||
|
|
db46326e95 | ||
|
|
44cc8d7a3c | ||
|
|
f8e097a061 | ||
|
|
37b3c22dee | ||
|
|
032178bea0 | ||
|
|
118cb3c9b1 | ||
|
|
717afebcff | ||
|
|
ec3ec9068c | ||
|
|
f755cfef48 | ||
|
|
c1f4b86d34 | ||
|
|
fcc398831b | ||
|
|
9da07590bd | ||
|
|
0cfedbc5f5 | ||
|
|
3608abb01a | ||
|
|
4739a0616d | ||
|
|
6e38ad9cce | ||
|
|
4599aff07f | ||
|
|
0b605333d9 | ||
|
|
9c18de993d | ||
|
|
e3dbd9ce4a | ||
|
|
c2480b29f7 | ||
|
|
6ac8633363 | ||
|
|
8a4c2f505f | ||
|
|
ca3077d034 | ||
|
|
6c89aa5227 | ||
|
|
8cb57566c0 | ||
|
|
18e6c6c2a8 | ||
|
|
e402993c34 | ||
|
|
754c34c120 | ||
|
|
2883ca839e | ||
|
|
fb6aad28bd | ||
|
|
ab76834100 | ||
|
|
ada2f5c767 | ||
|
|
e4af1f3319 | ||
|
|
ab0e382829 | ||
|
|
ed0b8e4af5 | ||
|
|
8a570b18e9 | ||
|
|
deb0168c09 | ||
|
|
46a12d0127 | ||
|
|
6d4baec955 | ||
|
|
4eaa06d58e | ||
|
|
0fe28a6459 | ||
|
|
aaeb4582e2 | ||
|
|
fdb0a14812 | ||
|
|
0324d1740e | ||
|
|
ce325db4e4 | ||
|
|
74e6736c79 | ||
|
|
2ed7608ed3 | ||
|
|
eb02acfc4b | ||
|
|
4f19d516d6 | ||
|
|
3dd918b024 | ||
|
|
8320018978 | ||
|
|
c17f2ff6b0 | ||
|
|
46a2ef8ba1 | ||
|
|
17c1d016c1 | ||
|
|
70ed791709 | ||
|
|
d39f63feca | ||
|
|
6882f006ac | ||
|
|
9a047a6996 | ||
|
|
a8bd839223 | ||
|
|
a1aef4c15c | ||
|
|
cb7598b007 | ||
|
|
55cf49cebe | ||
|
|
933f60a3c1 | ||
|
|
44eb048098 | ||
|
|
794ce57356 | ||
|
|
48d9715bd5 | ||
|
|
c5e1be4fd7 | ||
|
|
e21401004b | ||
|
|
120137eb8d | ||
|
|
2911eda3bd | ||
|
|
f1ea37dd71 | ||
|
|
3d3cbc0d16 | ||
|
|
d978440cb5 | ||
|
|
0c04ce3c32 | ||
|
|
987ce2c6b2 | ||
|
|
dded9290b7 | ||
|
|
745ef6e869 | ||
|
|
e2844bd0ad | ||
|
|
b67fda8832 | ||
|
|
d6e6d64848 | ||
|
|
f4d17d9a6b | ||
|
|
8bcb04af4a | ||
|
|
14e10f40e5 | ||
|
|
1c7105a940 |
119
.azure-pipelines/INSTALL.md
Normal file
119
.azure-pipelines/INSTALL.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Configuring Azure Pipelines with Certbot
|
||||
|
||||
Let's begin. All pipelines are defined in `.azure-pipelines`. Currently there are two:
|
||||
* `.azure-pipelines/main.yml` is the main one, executed on PRs for master, and pushes to master,
|
||||
* `.azure-pipelines/advanced.yml` add installer testing on top of the main pipeline, and is executed for `test-*` branches, release branches, and nightly run for master.
|
||||
|
||||
Several templates are defined in `.azure-pipelines/templates`. These YAML files aggregate common jobs configuration that can be reused in several pipelines.
|
||||
|
||||
Unlike Travis, where CodeCov is working without any action required, CodeCov supports Azure Pipelines
|
||||
using the coverage-bash utility (not python-coverage for now) only if you provide the Codecov repo token
|
||||
using the `CODECOV_TOKEN` environment variable. So `CODECOV_TOKEN` needs to be set as a secured
|
||||
environment variable to allow the main pipeline to publish coverage reports to CodeCov.
|
||||
|
||||
This INSTALL.md file explains how to configure Azure Pipelines with Certbot in order to execute the CI/CD logic defined in `.azure-pipelines` folder with it.
|
||||
During this installation step, warnings describing user access and legal comitments will be displayed like this:
|
||||
```
|
||||
!!! ACCESS REQUIRED !!!
|
||||
```
|
||||
|
||||
This document suppose that the Azure DevOps organization is named _certbot_, and the Azure DevOps project is also _certbot_.
|
||||
|
||||
## Useful links
|
||||
|
||||
* https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema
|
||||
* https://www.azuredevopslabs.com/labs/azuredevops/github-integration/
|
||||
* https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/python?view=azure-devops
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Having a GitHub account
|
||||
|
||||
Use your GitHub user for a normal GitHub account, or a user that has administrative rights to the GitHub organization if relevant.
|
||||
|
||||
### Having an Azure DevOps account
|
||||
- Go to https://dev.azure.com/, click "Start free with GitHub"
|
||||
- Login to GitHub
|
||||
|
||||
```
|
||||
!!! ACCESS REQUIRED !!!
|
||||
Personal user data (email + profile info, in read-only)
|
||||
```
|
||||
|
||||
- Microsoft will create a Live account using the email referenced for the GitHub account. This account is also linked to GitHub account (meaning you can log it using GitHub authentication)
|
||||
- Proceed with account registration (birth date, country), add details about name and email contact
|
||||
|
||||
```
|
||||
!!! ACCESS REQUIRED !!!
|
||||
Microsoft proposes to send commercial links to this mail
|
||||
Azure DevOps terms of service need to be accepted
|
||||
```
|
||||
|
||||
_Logged to Azure DevOps, account is ready._
|
||||
|
||||
### Installing Azure Pipelines to GitHub
|
||||
|
||||
- On GitHub, go to Marketplace
|
||||
- Select Azure Pipeline, and "Set up a plan"
|
||||
- Select Free, then "Install it for free"
|
||||
- Click "Complete order and begin installation"
|
||||
|
||||
```
|
||||
!!! ACCESS !!!
|
||||
Azure Pipeline needs RW on code, RO on metadata, RW on checks, commit statuses, deployments, issues, pull requests.
|
||||
RW access here is required to allow update of the pipelines YAML files from Azure DevOps interface, and to
|
||||
update the status of builds and PRs on GitHub side when Azure Pipelines are triggered.
|
||||
Note however that no admin access is defined here: this means that Azure Pipelines cannot do anything with
|
||||
protected branches, like master, and cannot modify the security context around this on GitHub.
|
||||
Access can be defined for all or only selected repositories, which is nice.
|
||||
```
|
||||
|
||||
- Redirected to Azure DevOps, select the account created in _Having an Azure DevOps account_ section.
|
||||
- Select the organization, and click "Create a new project" (let's name it the same than the targetted github repo)
|
||||
- The Visibility is public, to profit from 10 parallel jobs
|
||||
|
||||
```
|
||||
!!! ACCESS !!!
|
||||
Azure Pipelines needs access to the GitHub account (in term of beeing able to check it is valid), and the Resources shared between the GitHub account and Azure Pipelines.
|
||||
```
|
||||
|
||||
_Done. We can move to pipelines configuration._
|
||||
|
||||
## Import an existing pipelines from `.azure-pipelines` folder
|
||||
|
||||
- On Azure DevOps, go to your organization (eg. _certbot_) then your project (eg. _certbot_)
|
||||
- Click "Pipelines" tab
|
||||
- Click "New pipeline"
|
||||
- Where is your code?: select "__Use the classic editor__"
|
||||
|
||||
__Warning: Do not choose the GitHub option in Where is your code? section. Indeed, this option will trigger an OAuth
|
||||
grant permissions from Azure Pipelines to GitHub in order to setup a GitHub OAuth Application. The permissions asked
|
||||
then are way too large (admin level on almost everything), while the classic approach does not add any more
|
||||
permissions, and works perfectly well.__
|
||||
|
||||
- Select GitHub in "Select your repository section", choose certbot/certbot in Repository, master in default branch.
|
||||
- Click on YAML option for "Select a template"
|
||||
- Choose a name for the pipeline (eg. test-pipeline), and browse to the actual pipeline YAML definition in the
|
||||
"YAML file path" input (eg. `.azure-pipelines/test-pipeline.yml`)
|
||||
- Click "Save & queue", choose the master branch to build the first pipeline, and click "Save and run" button.
|
||||
|
||||
_Done. Pipeline is operational. Repeat to add more pipelines from existing YAML files in `.azure-pipelines`._
|
||||
|
||||
## Add a secret variable to a pipeline (like `CODECOV_TOKEN`)
|
||||
|
||||
__NB: Following steps suppose that you already setup the YAML pipeline file to
|
||||
consume the secret variable that these steps will create as an environment variable.
|
||||
For a variable named `CODECOV_TOKEN` consuming the variable `codecov_token`,
|
||||
in the YAML file this setup would take the form of the following:
|
||||
```
|
||||
steps:
|
||||
- script: ./do_something_that_consumes_CODECOV_TOKEN # Eg. `codecov -F windows`
|
||||
env:
|
||||
CODECOV_TOKEN: $(codecov_token)
|
||||
```
|
||||
|
||||
To set up a variable that is shared between pipelines, follow the instructions
|
||||
at
|
||||
https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups.
|
||||
When adding variables to a group, don't forget to tick "Keep this value secret"
|
||||
if it shouldn't be shared publcily.
|
||||
20
.azure-pipelines/advanced.yml
Normal file
20
.azure-pipelines/advanced.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
# Advanced pipeline for isolated checks and release purpose
|
||||
trigger:
|
||||
- test-*
|
||||
- '*.x'
|
||||
pr:
|
||||
- test-*
|
||||
# This pipeline is also nightly run on master
|
||||
schedules:
|
||||
- cron: "0 4 * * *"
|
||||
displayName: Nightly build
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
always: true
|
||||
|
||||
jobs:
|
||||
# Any addition here should be reflected in the release pipeline.
|
||||
# It is advised to declare all jobs here as templates to improve maintainability.
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/installer-tests.yml
|
||||
12
.azure-pipelines/main.yml
Normal file
12
.azure-pipelines/main.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
trigger:
|
||||
# apache-parser-v2 is a temporary branch for doing work related to
|
||||
# rewriting the parser in the Apache plugin.
|
||||
- apache-parser-v2
|
||||
- master
|
||||
pr:
|
||||
- apache-parser-v2
|
||||
- master
|
||||
- '*.x'
|
||||
|
||||
jobs:
|
||||
- template: templates/tests-suite.yml
|
||||
13
.azure-pipelines/release.yml
Normal file
13
.azure-pipelines/release.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Release pipeline to build and deploy Certbot for Windows for GitHub release tags
|
||||
trigger:
|
||||
tags:
|
||||
include:
|
||||
- v*
|
||||
pr: none
|
||||
|
||||
jobs:
|
||||
# Any addition here should be reflected in the advanced pipeline.
|
||||
# It is advised to declare all jobs here as templates to improve maintainability.
|
||||
- template: templates/tests-suite.yml
|
||||
- template: templates/installer-tests.yml
|
||||
- template: templates/changelog.yml
|
||||
14
.azure-pipelines/templates/changelog.yml
Normal file
14
.azure-pipelines/templates/changelog.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
jobs:
|
||||
- job: changelog
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- bash: |
|
||||
CERTBOT_VERSION="$(python -c "import certbot; print(certbot.__version__)")"
|
||||
"${BUILD_REPOSITORY_LOCALPATH}\tools\extract_changelog.py" "${CERTBOT_VERSION}" >> "${BUILD_ARTIFACTSTAGINGDIRECTORY}/release_notes.md"
|
||||
displayName: Prepare changelog
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: changelog
|
||||
displayName: Publish changelog
|
||||
32
.azure-pipelines/templates/installer-tests.yml
Normal file
32
.azure-pipelines/templates/installer-tests.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
jobs:
|
||||
- job: installer
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: 3.7
|
||||
architecture: x86
|
||||
addToPath: true
|
||||
- script: python windows-installer/construct.py
|
||||
displayName: Build Certbot installer
|
||||
- task: CopyFiles@2
|
||||
inputs:
|
||||
sourceFolder: $(System.DefaultWorkingDirectory)/windows-installer/build/nsis
|
||||
contents: '*.exe'
|
||||
targetFolder: $(Build.ArtifactStagingDirectory)
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
artifact: windows-installer
|
||||
displayName: Publish Windows installer
|
||||
- script: $(Build.ArtifactStagingDirectory)\certbot-beta-installer-win32.exe /S
|
||||
displayName: Install Certbot
|
||||
- script: |
|
||||
python -m venv venv
|
||||
venv\Scripts\python tools\pip_install.py -e certbot-ci
|
||||
displayName: Prepare Certbot-CI
|
||||
- script: |
|
||||
set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH%
|
||||
venv\Scripts\python -m pytest certbot-ci\certbot_integration_tests\certbot_tests -n 4
|
||||
displayName: Run integration tests
|
||||
38
.azure-pipelines/templates/tests-suite.yml
Normal file
38
.azure-pipelines/templates/tests-suite.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
jobs:
|
||||
- job: test
|
||||
pool:
|
||||
vmImage: vs2017-win2016
|
||||
strategy:
|
||||
matrix:
|
||||
py35:
|
||||
PYTHON_VERSION: 3.5
|
||||
TOXENV: py35
|
||||
py37-cover:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: py37-cover
|
||||
integration-certbot:
|
||||
PYTHON_VERSION: 3.7
|
||||
TOXENV: integration-certbot
|
||||
PYTEST_ADDOPTS: --numprocesses 4
|
||||
variables:
|
||||
- group: certbot-common
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: $(PYTHON_VERSION)
|
||||
addToPath: true
|
||||
- script: python tools/pip_install.py -U tox coverage
|
||||
displayName: Install dependencies
|
||||
- script: python -m tox
|
||||
displayName: Run tox
|
||||
# We do not require codecov report upload to succeed. So to avoid to break the pipeline if
|
||||
# something goes wrong, each command is suffixed with a command that hides any non zero exit
|
||||
# codes and echoes an informative message instead.
|
||||
- bash: |
|
||||
curl -s https://codecov.io/bash -o codecov-bash || echo "Failed to download codecov-bash"
|
||||
chmod +x codecov-bash || echo "Failed to apply execute permissions on codecov-bash"
|
||||
./codecov-bash -F windows || echo "Codecov did not collect coverage reports"
|
||||
condition: in(variables['TOXENV'], 'py37-cover', 'integration-certbot')
|
||||
env:
|
||||
CODECOV_TOKEN: $(codecov_token)
|
||||
displayName: Publish coverage
|
||||
@@ -6,13 +6,13 @@ coverage:
|
||||
flags: linux
|
||||
# Fixed target instead of auto set by #7173, can
|
||||
# be removed when flags in Codecov are added back.
|
||||
target: 97.5
|
||||
target: 97.4
|
||||
threshold: 0.1
|
||||
base: auto
|
||||
windows:
|
||||
flags: windows
|
||||
# Fixed target instead of auto set by #7173, can
|
||||
# be removed when flags in Codecov are added back.
|
||||
target: 97.6
|
||||
target: 97.4
|
||||
threshold: 0.1
|
||||
base: auto
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
[run]
|
||||
omit = */setup.py
|
||||
|
||||
[report]
|
||||
omit = */setup.py
|
||||
|
||||
81
.travis.yml
81
.travis.yml
@@ -1,4 +1,5 @@
|
||||
language: python
|
||||
dist: xenial
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -8,6 +9,8 @@ before_script:
|
||||
- 'if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ulimit -n 1024 ; fi'
|
||||
# On Travis, the fastest parallelization for integration tests has proved to be 4.
|
||||
- 'if [[ "$TOXENV" == *"integration"* ]]; then export PYTEST_ADDOPTS="--numprocesses 4"; fi'
|
||||
# Use Travis retry feature for farm tests since they are flaky
|
||||
- 'if [[ "$TOXENV" == "travis-test-farm"* ]]; then export TRAVIS_RETRY=travis_retry; fi'
|
||||
- export TOX_TESTENV_PASSENV=TRAVIS
|
||||
|
||||
# Only build pushes to the master branch, PRs, and branches beginning with
|
||||
@@ -37,8 +40,6 @@ matrix:
|
||||
# Main test suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=pebble TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
|
||||
# This job is always executed, including on master
|
||||
@@ -60,19 +61,15 @@ matrix:
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
env: TOXENV='py27-{acme,apache,certbot,dns,nginx}-oldest'
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
- python: "3.4"
|
||||
env: TOXENV=py34
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
- python: "3.7"
|
||||
dist: xenial
|
||||
env: TOXENV=py37
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
- python: "3.8"
|
||||
env: TOXENV=py38
|
||||
<<: *not-on-master
|
||||
- sudo: required
|
||||
env: TOXENV=apache_compat
|
||||
@@ -86,8 +83,6 @@ matrix:
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
env: TOXENV=apacheconftest-with-pebble
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *not-on-master
|
||||
- python: "2.7"
|
||||
env: TOXENV=nginxroundtrip
|
||||
@@ -123,7 +118,6 @@ matrix:
|
||||
- secure: "f+j/Lj9s1lcuKo5sEFrlRd1kIAMnIJI4z0MTI7QF8jl9Fkmbx7KECGzw31TNgzrOSzxSapHbcueFYvNCLKST+kE/8ogMZBbwqXfEDuKpyF6BY3uYoJn+wPVE5pIb8Hhe08xPte8TTDSMIyHI3EyTfcAKrIreauoArePvh/cRvSw="
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
dist: xenial
|
||||
env: TOXENV=py37 CERTBOT_NO_PIN=1
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
@@ -138,21 +132,37 @@ matrix:
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration-certbot-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration-certbot-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration-nginx-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "2.7"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration-nginx-oldest
|
||||
# Ubuntu Trusty or older must be used because the oldest version of
|
||||
# cryptography we support cannot be compiled against the version of
|
||||
# OpenSSL in Xenial or newer.
|
||||
dist: trusty
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
@@ -166,9 +176,11 @@ matrix:
|
||||
env: TOXENV=py36
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
dist: xenial
|
||||
env: TOXENV=py37
|
||||
<<: *extended-test-suite
|
||||
- python: "3.8-dev"
|
||||
env: TOXENV=py38
|
||||
<<: *extended-test-suite
|
||||
- python: "3.4"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
@@ -200,17 +212,21 @@ matrix:
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
dist: xenial
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.7"
|
||||
dist: xenial
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
sudo: required
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- python: "3.8-dev"
|
||||
env: ACME_SERVER=boulder-v1 TOXENV=integration
|
||||
<<: *extended-test-suite
|
||||
- python: "3.8-dev"
|
||||
env: ACME_SERVER=boulder-v2 TOXENV=integration
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_jessie
|
||||
services: docker
|
||||
@@ -218,6 +234,9 @@ matrix:
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_centos6
|
||||
services: docker
|
||||
- sudo: required
|
||||
env: TOXENV=le_auto_oraclelinux6
|
||||
services: docker
|
||||
<<: *extended-test-suite
|
||||
- sudo: required
|
||||
env: TOXENV=docker_dev
|
||||
@@ -273,20 +292,24 @@ addons:
|
||||
# virtualenv is listed here explicitly to make sure it is upgraded when
|
||||
# CERTBOT_NO_PIN is set to work around failures we've seen when using an older
|
||||
# version of virtualenv.
|
||||
install: "tools/pip_install.py -U codecov tox virtualenv"
|
||||
script: tox
|
||||
install: 'tools/pip_install.py -U codecov tox virtualenv'
|
||||
# Most of the time TRAVIS_RETRY is an empty string, and has no effect on the
|
||||
# script command. It is set only to `travis_retry` during farm tests, in
|
||||
# order to trigger the Travis retry feature, and compensate the inherent
|
||||
# flakiness of these specific tests.
|
||||
script: '$TRAVIS_RETRY tox'
|
||||
|
||||
after_success: '[ "$TOXENV" == "py27-cover" ] && codecov -F linux'
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
# This is set to a secure variable to prevent forks from sending
|
||||
# notifications. This value was created by installing
|
||||
# https://github.com/travis-ci/travis.rb and running
|
||||
# `travis encrypt "chat.freenode.net#certbot-devel"`.
|
||||
- secure: "EWW66E2+KVPZyIPR8ViENZwfcup4Gx3/dlimmAZE0WuLwxDCshBBOd3O8Rf6pBokEoZlXM5eDT6XdyJj8n0DLslgjO62pExdunXpbcMwdY7l1ELxX2/UbnDTE6UnPYa09qVBHNG7156Z6yE0x2lH4M9Ykvp0G0cubjPQHylAwo0="
|
||||
on_cancel: never
|
||||
on_success: never
|
||||
on_failure: always
|
||||
#notifications:
|
||||
# email: false
|
||||
# irc:
|
||||
# channels:
|
||||
# # This is set to a secure variable to prevent forks from sending
|
||||
# # notifications. This value was created by installing
|
||||
# # https://github.com/travis-ci/travis.rb and running
|
||||
# # `travis encrypt "chat.freenode.net#certbot-devel"`.
|
||||
# - secure: "EWW66E2+KVPZyIPR8ViENZwfcup4Gx3/dlimmAZE0WuLwxDCshBBOd3O8Rf6pBokEoZlXM5eDT6XdyJj8n0DLslgjO62pExdunXpbcMwdY7l1ELxX2/UbnDTE6UnPYa09qVBHNG7156Z6yE0x2lH4M9Ykvp0G0cubjPQHylAwo0="
|
||||
# on_cancel: never
|
||||
# on_success: never
|
||||
# on_failure: always
|
||||
|
||||
@@ -18,6 +18,7 @@ Authors
|
||||
* [Alex Zorin](https://github.com/alexzorin)
|
||||
* [Amjad Mashaal](https://github.com/TheNavigat)
|
||||
* [Andrew Murray](https://github.com/radarhere)
|
||||
* [Andrzej Górski](https://github.com/andrzej3393)
|
||||
* [Anselm Levskaya](https://github.com/levskaya)
|
||||
* [Antoine Jacoutot](https://github.com/ajacoutot)
|
||||
* [asaph](https://github.com/asaph)
|
||||
@@ -127,6 +128,7 @@ Authors
|
||||
* [Joubin Jabbari](https://github.com/joubin)
|
||||
* [Juho Juopperi](https://github.com/jkjuopperi)
|
||||
* [Kane York](https://github.com/riking)
|
||||
* [Kenichi Maehashi](https://github.com/kmaehashi)
|
||||
* [Kenneth Skovhede](https://github.com/kenkendk)
|
||||
* [Kevin Burke](https://github.com/kevinburke)
|
||||
* [Kevin London](https://github.com/kevinlondon)
|
||||
@@ -162,8 +164,10 @@ Authors
|
||||
* [Michael Schumacher](https://github.com/schumaml)
|
||||
* [Michael Strache](https://github.com/Jarodiv)
|
||||
* [Michael Sverdlin](https://github.com/sveder)
|
||||
* [Michael Watters](https://github.com/blackknight36)
|
||||
* [Michal Moravec](https://github.com/https://github.com/Majkl578)
|
||||
* [Michal Papis](https://github.com/mpapis)
|
||||
* [Mickaël Schoentgen](https://github.com/BoboTiG)
|
||||
* [Minn Soe](https://github.com/MinnSoe)
|
||||
* [Min RK](https://github.com/minrk)
|
||||
* [Miquel Ruiz](https://github.com/miquelruiz)
|
||||
@@ -227,6 +231,7 @@ Authors
|
||||
* [Stavros Korokithakis](https://github.com/skorokithakis)
|
||||
* [Stefan Weil](https://github.com/stweil)
|
||||
* [Steve Desmond](https://github.com/stevedesmond-ca)
|
||||
* [sydneyli](https://github.com/sydneyli)
|
||||
* [Tan Jay Jun](https://github.com/jayjun)
|
||||
* [Tapple Gao](https://github.com/tapple)
|
||||
* [Telepenin Nikolay](https://github.com/telepenin)
|
||||
|
||||
128
CHANGELOG.md
128
CHANGELOG.md
@@ -2,7 +2,128 @@
|
||||
|
||||
Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## 0.37.0 - master
|
||||
## 1.0.0 - master
|
||||
|
||||
### Added
|
||||
|
||||
*
|
||||
|
||||
### Changed
|
||||
|
||||
* Certbot's `config_changes` subcommand has been removed
|
||||
* The functions `certbot.client.view_config_changes`,
|
||||
`certbot.main.config_changes`,
|
||||
`certbot.plugins.common.Installer.view_config_changes`, and
|
||||
`certbot.reverter.Reverter.view_config_changes` have been removed
|
||||
|
||||
### Fixed
|
||||
|
||||
*
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.40.1 - 2019-11-05
|
||||
|
||||
### Changed
|
||||
|
||||
* Added back support for Python 3.4 to Certbot components and certbot-auto due
|
||||
to a bug when requiring Python 2.7 or 3.5+ on RHEL 6 based systems.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.40.0 - 2019-11-05
|
||||
|
||||
### Added
|
||||
|
||||
*
|
||||
|
||||
### Changed
|
||||
|
||||
* We deprecated support for Python 3.4 in Certbot and its ACME library. Support
|
||||
for Python 3.4 will be removed in the next major release of Certbot.
|
||||
certbot-auto users on RHEL 6 based systems will be asked to enable Software
|
||||
Collections (SCL) repository so Python 3.6 can be installed. certbot-auto can
|
||||
enable the SCL repo for you on CentOS 6 while users on other RHEL 6 based
|
||||
systems will be asked to do this manually.
|
||||
* `--server` may now be combined with `--dry-run`. Certbot will, as before, use the
|
||||
staging server instead of the live server when `--dry-run` is used.
|
||||
* `--dry-run` now requests fresh authorizations every time, fixing the issue
|
||||
where it was prone to falsely reporting success.
|
||||
* Updated certbot-dns-google to depend on newer versions of
|
||||
google-api-python-client and oauth2client.
|
||||
* The OS detection logic again uses distro library for Linux OSes
|
||||
* certbot.plugins.common.TLSSNI01 has been deprecated and will be removed in a
|
||||
future release.
|
||||
* CLI flags --tls-sni-01-port and --tls-sni-01-address have been removed.
|
||||
* The values tls-sni and tls-sni-01 for the --preferred-challenges flag are no
|
||||
longer accepted.
|
||||
* Removed the flags: `--agree-dev-preview`, `--dialog`, and `--apache-init-script`
|
||||
* acme.standalone.BaseRequestHandlerWithLogging and
|
||||
acme.standalone.simple_tls_sni_01_server have been deprecated and will be
|
||||
removed in a future release of the library.
|
||||
|
||||
### Fixed
|
||||
|
||||
*
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.39.0 - 2019-10-01
|
||||
|
||||
### Added
|
||||
|
||||
* Support for Python 3.8 was added to Certbot and all of its components.
|
||||
* Support for CentOS 8 was added to certbot-auto.
|
||||
|
||||
### Changed
|
||||
|
||||
* Don't send OCSP requests for expired certificates
|
||||
* Return to using platform.linux_distribution instead of distro.linux_distribution in OS fingerprinting for Python < 3.8
|
||||
* Updated the Nginx plugin's TLS configuration to keep support for some versions of IE11.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed OS detection in the Apache plugin on RHEL 6.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.38.0 - 2019-09-03
|
||||
|
||||
### Added
|
||||
|
||||
* Disable session tickets for Nginx users when appropriate.
|
||||
|
||||
### Changed
|
||||
|
||||
* If Certbot fails to rollback your server configuration, the error message
|
||||
links to the Let's Encrypt forum. Change the link to the Help category now
|
||||
that the Server category has been closed.
|
||||
* Replace platform.linux_distribution with distro.linux_distribution as a step
|
||||
towards Python 3.8 support in Certbot.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed OS detection in the Apache plugin on Scientific Linux.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.37.2 - 2019-08-21
|
||||
|
||||
* Stop disabling TLS session tickets in Nginx as it caused TLS failures on
|
||||
some systems.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.37.1 - 2019-08-08
|
||||
|
||||
### Fixed
|
||||
|
||||
* Stop disabling TLS session tickets in Apache as it caused TLS failures on
|
||||
some systems.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
## 0.37.0 - 2019-08-07
|
||||
|
||||
### Added
|
||||
|
||||
@@ -11,11 +132,12 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
### Changed
|
||||
|
||||
*
|
||||
* Follow updated Mozilla recommendations for Nginx ssl_protocols, ssl_ciphers,
|
||||
and ssl_prefer_server_ciphers
|
||||
|
||||
### Fixed
|
||||
|
||||
*
|
||||
* Fix certbot-auto failures on RHEL 8.
|
||||
|
||||
More details about these changes can be found on our GitHub repo.
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class _TLSSNI01DeprecationModule(object):
|
||||
self.__dict__['_module'] = module
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if 'TLSSNI01' in attr:
|
||||
if 'TLSSNI01' in attr or attr == 'BaseRequestHandlerWithLogging':
|
||||
warnings.warn('{0} attribute is deprecated, and will be removed soon.'.format(attr),
|
||||
DeprecationWarning, stacklevel=2)
|
||||
return getattr(self._module, attr)
|
||||
@@ -48,3 +48,10 @@ class _TLSSNI01DeprecationModule(object):
|
||||
|
||||
def __dir__(self): # pragma: no cover
|
||||
return ['_module'] + dir(self._module)
|
||||
|
||||
if sys.version_info[:2] == (3, 4):
|
||||
warnings.warn(
|
||||
"Python 3.4 support will be dropped in the next release of "
|
||||
"acme. Please upgrade your Python version.",
|
||||
PendingDeprecationWarning,
|
||||
) # pragma: no cover
|
||||
|
||||
@@ -136,7 +136,8 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
body = messages.UpdateAuthorization(status='deactivated')
|
||||
response = self._post(authzr.uri, body)
|
||||
return self._authzr_from_response(response)
|
||||
return self._authzr_from_response(response,
|
||||
authzr.body.identifier, authzr.uri)
|
||||
|
||||
def _authzr_from_response(self, response, identifier=None, uri=None):
|
||||
authzr = messages.AuthorizationResource(
|
||||
|
||||
@@ -7,6 +7,7 @@ import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import warnings
|
||||
|
||||
from six.moves import BaseHTTPServer # type: ignore # pylint: disable=import-error
|
||||
from six.moves import http_client # pylint: disable=import-error
|
||||
@@ -267,6 +268,9 @@ class HTTP01RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
def simple_tls_sni_01_server(cli_args, forever=True):
|
||||
"""Run simple standalone TLSSNI01 server."""
|
||||
warnings.warn(
|
||||
'simple_tls_sni_01_server is deprecated and will be removed soon.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -299,7 +303,3 @@ def simple_tls_sni_01_server(cli_args, forever=True):
|
||||
|
||||
# Patching ourselves to warn about TLS-SNI challenge deprecation and removal.
|
||||
sys.modules[__name__] = _TLSSNI01DeprecationModule(sys.modules[__name__])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(simple_tls_sni_01_server(sys.argv)) # pragma: no cover
|
||||
|
||||
@@ -6,6 +6,7 @@ import socket
|
||||
import threading
|
||||
import tempfile
|
||||
import unittest
|
||||
import warnings
|
||||
import time
|
||||
from contextlib import closing
|
||||
|
||||
@@ -67,6 +68,18 @@ class TLSSNI01ServerTest(unittest.TestCase):
|
||||
jose.ComparableX509(self.certs[b'localhost'][1]))
|
||||
|
||||
|
||||
class BaseRequestHandlerWithLoggingTest(unittest.TestCase):
|
||||
"""Test for acme.standalone.BaseRequestHandlerWithLogging."""
|
||||
|
||||
def test_it(self):
|
||||
with mock.patch('acme.standalone.warnings.warn') as mock_warn:
|
||||
# pylint: disable=unused-variable
|
||||
from acme.standalone import BaseRequestHandlerWithLogging
|
||||
self.assertTrue(mock_warn.called)
|
||||
msg = mock_warn.call_args[0][0]
|
||||
self.assertTrue(msg.startswith('BaseRequestHandlerWithLogging'))
|
||||
|
||||
|
||||
class HTTP01ServerTest(unittest.TestCase):
|
||||
"""Tests for acme.standalone.HTTP01Server."""
|
||||
|
||||
@@ -266,8 +279,7 @@ class TestSimpleTLSSNI01Server(unittest.TestCase):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.port = sock.getsockname()[1]
|
||||
|
||||
from acme.standalone import simple_tls_sni_01_server
|
||||
self.process = multiprocessing.Process(target=simple_tls_sni_01_server,
|
||||
self.process = multiprocessing.Process(target=_simple_tls_sni_01_server_no_warnings,
|
||||
args=(['path', '-p', str(self.port)],))
|
||||
self.old_cwd = os.getcwd()
|
||||
os.chdir(self.test_cwd)
|
||||
@@ -284,8 +296,8 @@ class TestSimpleTLSSNI01Server(unittest.TestCase):
|
||||
|
||||
@mock.patch('acme.standalone.TLSSNI01Server.handle_request')
|
||||
def test_mock(self, handle):
|
||||
from acme.standalone import simple_tls_sni_01_server
|
||||
simple_tls_sni_01_server(cli_args=['path', '-p', str(self.port)], forever=False)
|
||||
_simple_tls_sni_01_server_no_warnings(cli_args=['path', '-p', str(self.port)],
|
||||
forever=False)
|
||||
self.assertEqual(handle.call_count, 1)
|
||||
|
||||
def test_live(self):
|
||||
@@ -302,5 +314,12 @@ class TestSimpleTLSSNI01Server(unittest.TestCase):
|
||||
test_util.load_comparable_cert('rsa2048_cert.pem'))
|
||||
|
||||
|
||||
def _simple_tls_sni_01_server_no_warnings(*args, **kwargs):
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', 'simple_tls.*')
|
||||
from acme.standalone import simple_tls_sni_01_server
|
||||
return simple_tls_sni_01_server(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main() # pragma: no cover
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
"""
|
||||
import os
|
||||
import unittest
|
||||
import pkg_resources
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@@ -73,23 +72,3 @@ def load_pyopenssl_private_key(*names):
|
||||
loader = _guess_loader(
|
||||
names[-1], crypto.FILETYPE_PEM, crypto.FILETYPE_ASN1)
|
||||
return crypto.load_privatekey(loader, load_vector(*names))
|
||||
|
||||
|
||||
def skip_unless(condition, reason): # pragma: no cover
|
||||
"""Skip tests unless a condition holds.
|
||||
|
||||
This implements the basic functionality of unittest.skipUnless
|
||||
which is only available on Python 2.7+.
|
||||
|
||||
:param bool condition: If ``False``, the test will be skipped
|
||||
:param str reason: the reason for skipping the test
|
||||
|
||||
:rtype: callable
|
||||
:returns: decorator that hides tests unless condition is ``True``
|
||||
|
||||
"""
|
||||
if hasattr(unittest, "skipUnless"):
|
||||
return unittest.skipUnless(condition, reason)
|
||||
elif condition:
|
||||
return lambda cls: cls
|
||||
return lambda cls: None
|
||||
|
||||
@@ -3,7 +3,7 @@ from setuptools import find_packages
|
||||
from setuptools.command.test import test as TestCommand
|
||||
import sys
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
@@ -73,6 +73,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
],
|
||||
|
||||
44
appveyor.yml
44
appveyor.yml
@@ -1,44 +0,0 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- TOXENV: py35
|
||||
- TOXENV: py37-cover
|
||||
|
||||
branches:
|
||||
only:
|
||||
# apache-parser-v2 is a temporary branch for doing work related to
|
||||
# rewriting the parser in the Apache plugin.
|
||||
- apache-parser-v2
|
||||
- master
|
||||
- /^\d+\.\d+\.x$/ # Version branches like X.X.X
|
||||
- /^test-.*$/
|
||||
|
||||
init:
|
||||
# Since master can receive only commits from PR that have already been tested, following
|
||||
# condition avoid to launch all jobs except the coverage one for commits pushed to master.
|
||||
- ps: |
|
||||
if (-Not $Env:APPVEYOR_PULL_REQUEST_NUMBER -And $Env:APPVEYOR_REPO_BRANCH -Eq 'master' `
|
||||
-And -Not ($Env:TOXENV -Like '*-cover'))
|
||||
{ $Env:APPVEYOR_SKIP_FINALIZE_ON_EXIT = 'true'; Exit-AppVeyorBuild }
|
||||
|
||||
install:
|
||||
# Use Python 3.7 by default
|
||||
- "SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%"
|
||||
# Check env
|
||||
- "python --version"
|
||||
# Upgrade pip to avoid warnings
|
||||
- "python -m pip install --upgrade pip"
|
||||
# Ready to install tox and coverage
|
||||
# tools/pip_install.py is used to pin packages to a known working version.
|
||||
- "python tools\\pip_install.py tox codecov"
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- set TOX_TESTENV_PASSENV=APPVEYOR
|
||||
# Test env is set by TOXENV env variable
|
||||
- tox
|
||||
|
||||
on_success:
|
||||
- if exist .coverage codecov -F windows
|
||||
@@ -5,4 +5,3 @@ 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
|
||||
recursive-include certbot_apache/tls_configs *.conf
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
""" Utility functions for certbot-apache plugin """
|
||||
import binascii
|
||||
|
||||
import pkg_resources
|
||||
|
||||
from certbot import util
|
||||
from certbot.compat import os
|
||||
|
||||
@@ -107,15 +105,3 @@ def parse_define_file(filepath, varname):
|
||||
def unique_id():
|
||||
""" Returns an unique id to be used as a VirtualHost identifier"""
|
||||
return binascii.hexlify(os.urandom(16)).decode("utf-8")
|
||||
|
||||
|
||||
def find_ssl_apache_conf(prefix):
|
||||
"""
|
||||
Find a TLS Apache config file in the dedicated storage.
|
||||
:param str prefix: prefix of the TLS Apache config file to find
|
||||
:return: the path the TLS Apache config file
|
||||
:rtype: str
|
||||
"""
|
||||
return pkg_resources.resource_filename(
|
||||
"certbot_apache",
|
||||
os.path.join("tls_configs", "{0}-options-ssl-apache.conf".format(prefix)))
|
||||
|
||||
@@ -10,10 +10,16 @@ SSLEngine on
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
|
||||
SSLHonorCipherOrder on
|
||||
SSLSessionTickets off
|
||||
|
||||
SSLOptions +StrictRequire
|
||||
|
||||
# Add vhost name to log entries:
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
|
||||
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
|
||||
|
||||
#CustomLog /var/log/apache2/access.log vhost_combined
|
||||
#LogLevel warn
|
||||
#ErrorLog /var/log/apache2/error.log
|
||||
|
||||
# Always ensure Cookies have "Secure" set (JAH 2012/1)
|
||||
#Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"
|
||||
@@ -9,6 +9,7 @@ import time
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import pkg_resources
|
||||
import six
|
||||
|
||||
import zope.component
|
||||
@@ -109,24 +110,14 @@ class ApacheConfigurator(common.Installer):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def option(self, key):
|
||||
"""Get a value from options"""
|
||||
return self.options.get(key)
|
||||
|
||||
def pick_apache_config(self):
|
||||
"""
|
||||
Pick the appropriate TLS Apache configuration file for current version of Apache and OS.
|
||||
:return: the path to the TLS Apache configuration file to use
|
||||
:rtype: str
|
||||
"""
|
||||
# Disabling TLS session tickets is supported by Apache 2.4.11+.
|
||||
# So for old versions of Apache we pick a configuration without this option.
|
||||
if self.version < (2, 4, 11):
|
||||
return apache_util.find_ssl_apache_conf("old")
|
||||
return apache_util.find_ssl_apache_conf("current")
|
||||
|
||||
def _prepare_options(self):
|
||||
"""
|
||||
Set the values possibly changed by command line parameters to
|
||||
@@ -183,8 +174,6 @@ class ApacheConfigurator(common.Installer):
|
||||
"(Only Ubuntu/Debian currently)")
|
||||
add("ctl", default=DEFAULTS["ctl"],
|
||||
help="Full path to Apache control script")
|
||||
util.add_deprecated_argument(
|
||||
add, argument_name="init-script", nargs=1)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize an Apache Configurator.
|
||||
@@ -2348,9 +2337,8 @@ class ApacheConfigurator(common.Installer):
|
||||
# XXX if we ever try to enforce a local privilege boundary (eg, running
|
||||
# certbot for unprivileged users via setuid), this function will need
|
||||
# to be modified.
|
||||
apache_config_path = self.pick_apache_config()
|
||||
return common.install_version_controlled_file(
|
||||
options_ssl, options_ssl_digest, apache_config_path, constants.ALL_SSL_OPTIONS_HASHES)
|
||||
return common.install_version_controlled_file(options_ssl, options_ssl_digest,
|
||||
self.option("MOD_SSL_CONF_SRC"), constants.ALL_SSL_OPTIONS_HASHES)
|
||||
|
||||
def enable_autohsts(self, _unused_lineage, domains):
|
||||
"""
|
||||
|
||||
@@ -16,6 +16,7 @@ from certbot_apache import override_suse
|
||||
|
||||
OVERRIDE_CLASSES = {
|
||||
"arch": override_arch.ArchConfigurator,
|
||||
"cloudlinux": override_centos.CentOSConfigurator,
|
||||
"darwin": override_darwin.DarwinConfigurator,
|
||||
"debian": override_debian.DebianConfigurator,
|
||||
"ubuntu": override_debian.DebianConfigurator,
|
||||
@@ -23,7 +24,10 @@ OVERRIDE_CLASSES = {
|
||||
"centos linux": override_centos.CentOSConfigurator,
|
||||
"fedora_old": override_centos.CentOSConfigurator,
|
||||
"fedora": override_fedora.FedoraConfigurator,
|
||||
"linuxmint": override_debian.DebianConfigurator,
|
||||
"ol": override_centos.CentOSConfigurator,
|
||||
"oracle": override_centos.CentOSConfigurator,
|
||||
"redhatenterpriseserver": override_centos.CentOSConfigurator,
|
||||
"red hat enterprise linux server": override_centos.CentOSConfigurator,
|
||||
"rhel": override_centos.CentOSConfigurator,
|
||||
"amazon": override_centos.CentOSConfigurator,
|
||||
@@ -31,6 +35,9 @@ OVERRIDE_CLASSES = {
|
||||
"gentoo base system": override_gentoo.GentooConfigurator,
|
||||
"opensuse": override_suse.OpenSUSEConfigurator,
|
||||
"suse": override_suse.OpenSUSEConfigurator,
|
||||
"sles": override_suse.OpenSUSEConfigurator,
|
||||
"scientific": override_centos.CentOSConfigurator,
|
||||
"scientific linux": override_centos.CentOSConfigurator,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from certbot_apache.parser import get_aug_path
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApacheHttp01(common.TLSSNI01):
|
||||
class ApacheHttp01(common.ChallengePerformer):
|
||||
"""Class that performs HTTP-01 challenges within the Apache configurator."""
|
||||
|
||||
CONFIG_TEMPLATE22_PRE = """\
|
||||
|
||||
@@ -17,3 +17,10 @@ SSLOptions +StrictRequire
|
||||
# Add vhost name to log entries:
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
|
||||
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
|
||||
|
||||
#CustomLog /var/log/apache2/access.log vhost_combined
|
||||
#LogLevel warn
|
||||
#ErrorLog /var/log/apache2/error.log
|
||||
|
||||
# Always ensure Cookies have "Secure" set (JAH 2012/1)
|
||||
#Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"
|
||||
@@ -1,4 +1,6 @@
|
||||
""" Distribution specific override class for Arch Linux """
|
||||
import pkg_resources
|
||||
|
||||
import zope.interface
|
||||
|
||||
from certbot import interfaces
|
||||
@@ -24,4 +26,6 @@ class ArchConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
""" Distribution specific override class for CentOS family (RHEL, Fedora) """
|
||||
import logging
|
||||
|
||||
import pkg_resources
|
||||
import zope.interface
|
||||
|
||||
from certbot import errors
|
||||
@@ -38,6 +39,8 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf.d",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "centos-options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def config_test(self):
|
||||
@@ -72,18 +75,6 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
|
||||
# Finish with actual config check to see if systemctl restart helped
|
||||
super(CentOSConfigurator, self).config_test()
|
||||
|
||||
def pick_apache_config(self):
|
||||
"""
|
||||
Pick the appropriate TLS Apache configuration file for current version of Apache and OS.
|
||||
:return: the path to the TLS Apache configuration file to use
|
||||
:rtype: str
|
||||
"""
|
||||
# Disabling TLS session tickets is supported by Apache 2.4.11+.
|
||||
# So for old versions of Apache we pick a configuration without this option.
|
||||
if self.version < (2, 4, 11):
|
||||
return apache_util.find_ssl_apache_conf("centos-old")
|
||||
return apache_util.find_ssl_apache_conf("centos-current")
|
||||
|
||||
def _prepare_options(self):
|
||||
"""
|
||||
Override the options dictionary initialization in order to support
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
""" Distribution specific override class for macOS """
|
||||
import pkg_resources
|
||||
|
||||
import zope.interface
|
||||
|
||||
from certbot import interfaces
|
||||
@@ -24,4 +26,6 @@ class DarwinConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/other",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
""" Distribution specific override class for Debian family (Ubuntu/Debian) """
|
||||
import logging
|
||||
|
||||
import pkg_resources
|
||||
import zope.interface
|
||||
|
||||
from certbot import errors
|
||||
@@ -34,6 +35,8 @@ class DebianConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=True,
|
||||
handle_sites=True,
|
||||
challenge_location="/etc/apache2",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def enable_site(self, vhost):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
""" Distribution specific override class for Fedora 29+ """
|
||||
import pkg_resources
|
||||
import zope.interface
|
||||
|
||||
from certbot import errors
|
||||
@@ -30,6 +31,9 @@ class FedoraConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/httpd/conf.d",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
# TODO: eventually newest version of Fedora will need their own config
|
||||
"certbot_apache", "centos-options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def config_test(self):
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
""" Distribution specific override class for Gentoo Linux """
|
||||
import pkg_resources
|
||||
|
||||
import zope.interface
|
||||
|
||||
from certbot import interfaces
|
||||
@@ -27,6 +29,8 @@ class GentooConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/vhosts.d",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
def _prepare_options(self):
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
""" Distribution specific override class for OpenSUSE """
|
||||
import pkg_resources
|
||||
|
||||
import zope.interface
|
||||
|
||||
from certbot import interfaces
|
||||
@@ -24,4 +26,6 @@ class OpenSUSEConfigurator(configurator.ApacheConfigurator):
|
||||
handle_modules=False,
|
||||
handle_sites=False,
|
||||
challenge_location="/etc/apache2/vhosts.d",
|
||||
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
|
||||
"certbot_apache", "options-ssl-apache.conf")
|
||||
)
|
||||
|
||||
@@ -190,13 +190,6 @@ class MultipleVhostsTestCentOS(util.ApacheTest):
|
||||
errors.SubprocessError]
|
||||
self.assertRaises(errors.MisconfigurationError, self.config.restart)
|
||||
|
||||
def test_pick_correct_tls_config(self):
|
||||
self.config.version = (2, 4, 10)
|
||||
self.assertTrue('centos-old' in self.config.pick_apache_config())
|
||||
|
||||
self.config.version = (2, 4, 11)
|
||||
self.assertTrue('centos-current' in self.config.pick_apache_config())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main() # pragma: no cover
|
||||
|
||||
@@ -108,13 +108,9 @@ class MultipleVhostsTest(util.ApacheTest):
|
||||
exp[k.replace("_", "-")] = ApacheConfigurator.OS_DEFAULTS[k]
|
||||
# Special cases
|
||||
exp["vhost-root"] = None
|
||||
exp["init-script"] = None
|
||||
|
||||
found = set()
|
||||
for call in mock_add.call_args_list:
|
||||
# init-script is a special case: deprecated argument
|
||||
if call[0][0] != "init-script":
|
||||
self.assertEqual(exp[call[0][0]], call[1]['default'])
|
||||
found.add(call[0][0])
|
||||
|
||||
# Make sure that all (and only) the expected values exist
|
||||
@@ -1296,13 +1292,13 @@ class MultipleVhostsTest(util.ApacheTest):
|
||||
account_key = self.rsa512jwk
|
||||
achall1 = achallenges.KeyAuthorizationAnnotatedChallenge(
|
||||
challb=acme_util.chall_to_challb(
|
||||
challenges.TLSSNI01(
|
||||
challenges.HTTP01(
|
||||
token=b"jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q"),
|
||||
"pending"),
|
||||
domain="encryption-example.demo", account_key=account_key)
|
||||
achall2 = achallenges.KeyAuthorizationAnnotatedChallenge(
|
||||
challb=acme_util.chall_to_challb(
|
||||
challenges.TLSSNI01(
|
||||
challenges.HTTP01(
|
||||
token=b"uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"),
|
||||
"pending"),
|
||||
domain="certbot.demo", account_key=account_key)
|
||||
@@ -1706,7 +1702,7 @@ class InstallSslOptionsConfTest(util.ApacheTest):
|
||||
self.config.updated_mod_ssl_conf_digest)
|
||||
|
||||
def _current_ssl_options_hash(self):
|
||||
return crypto_util.sha256sum(self.config.pick_apache_config())
|
||||
return crypto_util.sha256sum(self.config.option("MOD_SSL_CONF_SRC"))
|
||||
|
||||
def _assert_current_file(self):
|
||||
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
||||
@@ -1742,7 +1738,7 @@ class InstallSslOptionsConfTest(util.ApacheTest):
|
||||
self.assertFalse(mock_logger.warning.called)
|
||||
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
|
||||
self.assertEqual(crypto_util.sha256sum(
|
||||
self.config.pick_apache_config()),
|
||||
self.config.option("MOD_SSL_CONF_SRC")),
|
||||
self._current_ssl_options_hash())
|
||||
self.assertNotEqual(crypto_util.sha256sum(self.config.mod_ssl_conf),
|
||||
self._current_ssl_options_hash())
|
||||
@@ -1758,31 +1754,18 @@ class InstallSslOptionsConfTest(util.ApacheTest):
|
||||
"%s has been manually modified; updated file "
|
||||
"saved to %s. We recommend updating %s for security purposes.")
|
||||
self.assertEqual(crypto_util.sha256sum(
|
||||
self.config.pick_apache_config()),
|
||||
self.config.option("MOD_SSL_CONF_SRC")),
|
||||
self._current_ssl_options_hash())
|
||||
# only print warning once
|
||||
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
||||
self._call()
|
||||
self.assertFalse(mock_logger.warning.called)
|
||||
|
||||
def test_ssl_config_files_hash_in_all_hashes(self):
|
||||
"""
|
||||
It is really critical that all TLS Apache config files have their SHA256 hash registered in
|
||||
constants.ALL_SSL_OPTIONS_HASHES. Otherwise Certbot will mistakenly assume that the config
|
||||
file has been manually edited by the user, and will refuse to update it.
|
||||
This test ensures that all necessary hashes are present.
|
||||
"""
|
||||
def test_current_file_hash_in_all_hashes(self):
|
||||
from certbot_apache.constants import ALL_SSL_OPTIONS_HASHES
|
||||
import pkg_resources
|
||||
tls_configs_dir = pkg_resources.resource_filename("certbot_apache", "tls_configs")
|
||||
all_files = [os.path.join(tls_configs_dir, name) for name in os.listdir(tls_configs_dir)
|
||||
if name.endswith('options-ssl-apache.conf')]
|
||||
self.assertTrue(all_files)
|
||||
for one_file in all_files:
|
||||
file_hash = crypto_util.sha256sum(one_file)
|
||||
self.assertTrue(file_hash in ALL_SSL_OPTIONS_HASHES,
|
||||
"Constants.ALL_SSL_OPTIONS_HASHES must be appended with the sha256 "
|
||||
"hash of {0} when it is updated.".format(one_file))
|
||||
self.assertTrue(self._current_ssl_options_hash() in ALL_SSL_OPTIONS_HASHES,
|
||||
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
|
||||
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -7,6 +7,7 @@ from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-
|
||||
|
||||
from certbot import achallenges
|
||||
from certbot import errors
|
||||
from certbot.compat import filesystem
|
||||
from certbot.compat import os
|
||||
from certbot.tests import acme_util
|
||||
|
||||
@@ -180,7 +181,7 @@ class ApacheHttp01Test(util.ApacheTest):
|
||||
self.assertEqual(self.http.perform(), expected_response)
|
||||
|
||||
self.assertTrue(os.path.isdir(self.http.challenge_dir))
|
||||
self._has_min_permissions(self.http.challenge_dir, 0o755)
|
||||
self.assertTrue(filesystem.has_min_permissions(self.http.challenge_dir, 0o755))
|
||||
self._test_challenge_conf()
|
||||
|
||||
for achall in achalls:
|
||||
@@ -218,15 +219,10 @@ class ApacheHttp01Test(util.ApacheTest):
|
||||
name = os.path.join(self.http.challenge_dir, achall.chall.encode("token"))
|
||||
validation = achall.validation(self.account_key)
|
||||
|
||||
self._has_min_permissions(name, 0o644)
|
||||
self.assertTrue(filesystem.has_min_permissions(name, 0o644))
|
||||
with open(name, 'rb') as f:
|
||||
self.assertEqual(f.read(), validation.encode())
|
||||
|
||||
def _has_min_permissions(self, path, min_mode):
|
||||
"""Tests the given file has at least the permissions in mode."""
|
||||
st_mode = os.stat(path).st_mode
|
||||
self.assertEqual(st_mode, st_mode | min_mode)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main() # pragma: no cover
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
SSLEngine on
|
||||
|
||||
# Intermediate configuration, tweak to your needs
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
|
||||
SSLHonorCipherOrder on
|
||||
|
||||
SSLOptions +StrictRequire
|
||||
|
||||
# Add vhost name to log entries:
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
|
||||
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
|
||||
@@ -1,20 +0,0 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
SSLEngine on
|
||||
|
||||
# Intermediate configuration, tweak to your needs
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
|
||||
SSLHonorCipherOrder on
|
||||
SSLCompression off
|
||||
SSLSessionTickets off
|
||||
|
||||
SSLOptions +StrictRequire
|
||||
|
||||
# Add vhost name to log entries:
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
|
||||
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
|
||||
@@ -1,5 +0,0 @@
|
||||
:mod:`certbot_apache.tls_sni_01`
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: certbot_apache.tls_sni_01
|
||||
:members:
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
-e .[dev]
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
|
||||
import sys
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.37.0.dev0',
|
||||
'certbot>=0.39.0',
|
||||
'mock',
|
||||
'python-augeas',
|
||||
'setuptools',
|
||||
@@ -62,6 +62,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
230
certbot-auto
230
certbot-auto
@@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
|
||||
fi
|
||||
VENV_BIN="$VENV_PATH/bin"
|
||||
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
|
||||
LE_AUTO_VERSION="0.36.0"
|
||||
LE_AUTO_VERSION="0.40.1"
|
||||
BASENAME=$(basename $0)
|
||||
USAGE="Usage: $BASENAME [OPTIONS]
|
||||
A self-updating wrapper script for the Certbot ACME client. When run, updates
|
||||
@@ -755,13 +755,33 @@ elif [ -f /etc/redhat-release ]; then
|
||||
prev_le_python="$LE_PYTHON"
|
||||
unset LE_PYTHON
|
||||
DeterminePythonVersion "NOCRASH"
|
||||
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
|
||||
|
||||
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
|
||||
RPM_DIST_VERSION=0
|
||||
if [ "$RPM_DIST_NAME" = "fedora" ]; then
|
||||
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) || echo "0"`
|
||||
|
||||
# Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
|
||||
# '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
|
||||
# error, RPM_DIST_VERSION is set to "unknown".
|
||||
RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
|
||||
|
||||
# If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
|
||||
# characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
|
||||
if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
|
||||
RPM_DIST_VERSION=0
|
||||
fi
|
||||
|
||||
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
|
||||
# RHEL 8 also uses python3 by default.
|
||||
if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
|
||||
RPM_USE_PYTHON_3=1
|
||||
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
|
||||
RPM_USE_PYTHON_3=1
|
||||
elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then
|
||||
RPM_USE_PYTHON_3=1
|
||||
else
|
||||
RPM_USE_PYTHON_3=0
|
||||
fi
|
||||
|
||||
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
|
||||
Bootstrap() {
|
||||
BootstrapMessage "RedHat-based OSes that will use Python3"
|
||||
BootstrapRpmPython3
|
||||
@@ -775,6 +795,7 @@ elif [ -f /etc/redhat-release ]; then
|
||||
}
|
||||
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
|
||||
fi
|
||||
|
||||
LE_PYTHON="$prev_le_python"
|
||||
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
|
||||
Bootstrap() {
|
||||
@@ -1115,73 +1136,76 @@ if [ "$1" = "--le-auto-phase2" ]; then
|
||||
# To generate this, do (with docker and package hashin installed):
|
||||
# ```
|
||||
# letsencrypt-auto-source/rebuild_dependencies.py \
|
||||
# letsencrypt-auto-sources/pieces/dependency-requirements.txt
|
||||
# letsencrypt-auto-source/pieces/dependency-requirements.txt
|
||||
# ```
|
||||
# If you want to update a single dependency, run commands similar to these:
|
||||
# ```
|
||||
# pip install hashin
|
||||
# hashin -r dependency-requirements.txt cryptography==1.5.2
|
||||
# ```
|
||||
ConfigArgParse==0.14.0 \
|
||||
--hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
|
||||
asn1crypto==0.24.0 \
|
||||
--hash=sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87 \
|
||||
--hash=sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49
|
||||
certifi==2019.3.9 \
|
||||
--hash=sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5 \
|
||||
--hash=sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae
|
||||
cffi==1.12.2 \
|
||||
--hash=sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f \
|
||||
--hash=sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11 \
|
||||
--hash=sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d \
|
||||
--hash=sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891 \
|
||||
--hash=sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf \
|
||||
--hash=sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c \
|
||||
--hash=sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed \
|
||||
--hash=sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b \
|
||||
--hash=sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a \
|
||||
--hash=sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585 \
|
||||
--hash=sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea \
|
||||
--hash=sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f \
|
||||
--hash=sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33 \
|
||||
--hash=sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145 \
|
||||
--hash=sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a \
|
||||
--hash=sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3 \
|
||||
--hash=sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f \
|
||||
--hash=sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd \
|
||||
--hash=sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804 \
|
||||
--hash=sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d \
|
||||
--hash=sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92 \
|
||||
--hash=sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f \
|
||||
--hash=sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84 \
|
||||
--hash=sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb \
|
||||
--hash=sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7 \
|
||||
--hash=sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7 \
|
||||
--hash=sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35 \
|
||||
--hash=sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889
|
||||
certifi==2019.6.16 \
|
||||
--hash=sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939 \
|
||||
--hash=sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695
|
||||
cffi==1.12.3 \
|
||||
--hash=sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774 \
|
||||
--hash=sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d \
|
||||
--hash=sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90 \
|
||||
--hash=sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b \
|
||||
--hash=sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63 \
|
||||
--hash=sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45 \
|
||||
--hash=sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25 \
|
||||
--hash=sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3 \
|
||||
--hash=sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b \
|
||||
--hash=sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647 \
|
||||
--hash=sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016 \
|
||||
--hash=sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4 \
|
||||
--hash=sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb \
|
||||
--hash=sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753 \
|
||||
--hash=sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7 \
|
||||
--hash=sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9 \
|
||||
--hash=sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f \
|
||||
--hash=sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8 \
|
||||
--hash=sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f \
|
||||
--hash=sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc \
|
||||
--hash=sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42 \
|
||||
--hash=sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3 \
|
||||
--hash=sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909 \
|
||||
--hash=sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45 \
|
||||
--hash=sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d \
|
||||
--hash=sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512 \
|
||||
--hash=sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff \
|
||||
--hash=sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201
|
||||
chardet==3.0.4 \
|
||||
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
|
||||
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
|
||||
configobj==5.0.6 \
|
||||
--hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
|
||||
cryptography==2.6.1 \
|
||||
--hash=sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1 \
|
||||
--hash=sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705 \
|
||||
--hash=sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6 \
|
||||
--hash=sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1 \
|
||||
--hash=sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8 \
|
||||
--hash=sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151 \
|
||||
--hash=sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d \
|
||||
--hash=sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659 \
|
||||
--hash=sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537 \
|
||||
--hash=sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e \
|
||||
--hash=sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb \
|
||||
--hash=sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c \
|
||||
--hash=sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9 \
|
||||
--hash=sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5 \
|
||||
--hash=sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad \
|
||||
--hash=sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a \
|
||||
--hash=sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460 \
|
||||
--hash=sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd \
|
||||
--hash=sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6
|
||||
# Package enum34 needs to be explicitly limited to Python2.x, in order to avoid
|
||||
# certbot-auto failures on Python 3.6+ which enum34 doesn't support. See #5456.
|
||||
enum34==1.1.6 ; python_version < '3.4' \
|
||||
cryptography==2.7 \
|
||||
--hash=sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c \
|
||||
--hash=sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643 \
|
||||
--hash=sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216 \
|
||||
--hash=sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799 \
|
||||
--hash=sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a \
|
||||
--hash=sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9 \
|
||||
--hash=sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc \
|
||||
--hash=sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8 \
|
||||
--hash=sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53 \
|
||||
--hash=sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1 \
|
||||
--hash=sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609 \
|
||||
--hash=sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292 \
|
||||
--hash=sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e \
|
||||
--hash=sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6 \
|
||||
--hash=sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed \
|
||||
--hash=sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d
|
||||
distro==1.4.0 \
|
||||
--hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
|
||||
--hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
|
||||
enum34==1.1.6 \
|
||||
--hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
|
||||
--hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
|
||||
--hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
|
||||
@@ -1197,18 +1221,18 @@ idna==2.8 \
|
||||
ipaddress==1.0.22 \
|
||||
--hash=sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794 \
|
||||
--hash=sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c
|
||||
josepy==1.1.0 \
|
||||
--hash=sha256:1309a25aac3caeff5239729c58ff9b583f7d022ffdb1553406ddfc8e5b52b76e \
|
||||
--hash=sha256:fb5c62c77d26e04df29cb5ecd01b9ce69b6fcc9e521eb1ca193b7faa2afa7086
|
||||
josepy==1.2.0 \
|
||||
--hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
|
||||
--hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
|
||||
mock==1.3.0 \
|
||||
--hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
|
||||
--hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
|
||||
parsedatetime==2.4 \
|
||||
--hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
|
||||
--hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
|
||||
pbr==5.1.3 \
|
||||
--hash=sha256:8257baf496c8522437e8a6cfe0f15e00aedc6c0e0e7c9d55eeeeab31e0853843 \
|
||||
--hash=sha256:8c361cc353d988e4f5b998555c88098b9d5964c2e11acf7b0d21925a66bb5824
|
||||
pbr==5.4.2 \
|
||||
--hash=sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc \
|
||||
--hash=sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf
|
||||
pyOpenSSL==19.0.0 \
|
||||
--hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
|
||||
--hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
|
||||
@@ -1217,14 +1241,14 @@ pyRFC3339==1.1 \
|
||||
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
|
||||
pycparser==2.19 \
|
||||
--hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
|
||||
pyparsing==2.3.1 \
|
||||
--hash=sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a \
|
||||
--hash=sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3
|
||||
pyparsing==2.4.2 \
|
||||
--hash=sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80 \
|
||||
--hash=sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4
|
||||
python-augeas==0.5.0 \
|
||||
--hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
|
||||
pytz==2018.9 \
|
||||
--hash=sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9 \
|
||||
--hash=sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c
|
||||
pytz==2019.2 \
|
||||
--hash=sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32 \
|
||||
--hash=sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7
|
||||
requests==2.21.0 \
|
||||
--hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
|
||||
--hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
|
||||
@@ -1234,15 +1258,15 @@ requests-toolbelt==0.9.1 \
|
||||
six==1.12.0 \
|
||||
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
|
||||
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
|
||||
urllib3==1.24.2 \
|
||||
--hash=sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0 \
|
||||
--hash=sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3
|
||||
urllib3==1.24.3 \
|
||||
--hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
|
||||
--hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
|
||||
zope.component==4.5 \
|
||||
--hash=sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55 \
|
||||
--hash=sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4
|
||||
zope.deferredimport==4.3 \
|
||||
--hash=sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5 \
|
||||
--hash=sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec
|
||||
zope.deferredimport==4.3.1 \
|
||||
--hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
|
||||
--hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
|
||||
zope.deprecation==4.4.0 \
|
||||
--hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
|
||||
--hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
|
||||
@@ -1290,18 +1314,18 @@ zope.interface==4.6.0 \
|
||||
--hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
|
||||
--hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
|
||||
--hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
|
||||
zope.proxy==4.3.1 \
|
||||
--hash=sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b \
|
||||
--hash=sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd \
|
||||
--hash=sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb \
|
||||
--hash=sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2 \
|
||||
--hash=sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5 \
|
||||
--hash=sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475 \
|
||||
--hash=sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe \
|
||||
--hash=sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3 \
|
||||
--hash=sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08 \
|
||||
--hash=sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb \
|
||||
--hash=sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed
|
||||
zope.proxy==4.3.2 \
|
||||
--hash=sha256:320a7619992e42142549ebf61e14ce27683b4d14b0cbc45f7c037ba64edb560c \
|
||||
--hash=sha256:824d4dbabbb7deb84f25fdb96ea1eeca436a1802c3c8d323b3eb4ac9d527d41c \
|
||||
--hash=sha256:8a32eb9c94908f3544da2dae3f4a9e6961d78819b88ac6b6f4a51cee2d65f4a0 \
|
||||
--hash=sha256:96265fd3bc3ea646f98482e16307a69de21402eeaaaaf4b841c1161ac2f71bb0 \
|
||||
--hash=sha256:ab6d6975d9c51c13cac828ff03168de21fb562b0664c59bcdc4a4b10f39a5b17 \
|
||||
--hash=sha256:af10cb772391772463f65a58348e2de5ecc06693c16d2078be276dc068bcbb54 \
|
||||
--hash=sha256:b8fd3a3de3f7b6452775e92af22af5977b17b69ac86a38a3ddfe870e40a0d05f \
|
||||
--hash=sha256:bb7088f1bed3b8214284a5e425dc23da56f2f28e8815b7580bfed9e245b6c0b6 \
|
||||
--hash=sha256:bc29b3665eac34f14c4aef5224bef045efcfb1a7d12d78c8685858de5fbf21c0 \
|
||||
--hash=sha256:c39fa6a159affeae5fe31b49d9f5b12bd674fe77271a9a324408b271440c50a7 \
|
||||
--hash=sha256:e946a036ac5b9f897e986ac9dc950a34cffc857d88eae6727b8434fbc4752366
|
||||
|
||||
# Contains the requirements for the letsencrypt package.
|
||||
#
|
||||
@@ -1314,18 +1338,18 @@ letsencrypt==0.7.0 \
|
||||
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
|
||||
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
|
||||
|
||||
certbot==0.36.0 \
|
||||
--hash=sha256:486cee6c4861762fe4a94b4f44f7d227034d026d1a8d7ba2911ef4e86a737613 \
|
||||
--hash=sha256:bf6745b823644cdca8461150455aeb67d417f87f80b9ec774c716e9587ef20a2
|
||||
acme==0.36.0 \
|
||||
--hash=sha256:5570c8e87383fbc733224fd0f7d164313b67dd9c21deafe9ddc8e769441f0c86 \
|
||||
--hash=sha256:0461ee3c882d865e98e624561843dc135fa1a1412b15603d7ebfbb392de6a668
|
||||
certbot-apache==0.36.0 \
|
||||
--hash=sha256:2537f7fb67a38b6d1ed5ee79f6a799090ca609695ac3799bb840b2fb677ac98d \
|
||||
--hash=sha256:458d20a3e9e8a88563d3deb0bbe38752bd2b80100f0e5854e4069390c1b4e5cd
|
||||
certbot-nginx==0.36.0 \
|
||||
--hash=sha256:4303b54adf2030671c54bb3964c1f43aec0f677045e0cdb6d4fb931268d08310 \
|
||||
--hash=sha256:4c34e6114dd8204b6667f101579dd9ab2b38fef0dd5a15702585edcb2aefb322
|
||||
certbot==0.40.1 \
|
||||
--hash=sha256:afe4d7edc61d4cab8b6f7ab7611d66aaba67d9f0404fa2760bd1cc430b2ec9ec \
|
||||
--hash=sha256:8dc81b3044cf401c55fa36c30893887fcb92657df1d76a8848059683df3b10d1
|
||||
acme==0.40.1 \
|
||||
--hash=sha256:a85387c26fb4fc24511b2579b8c61177b3175fd25e130c5be95a840d9f67d54f \
|
||||
--hash=sha256:33bf8686408d5b6b79886a9a43aee691ca754408deaec4fb2bb17b9af48a5ffc
|
||||
certbot-apache==0.40.1 \
|
||||
--hash=sha256:6c4a4e21a17bd8120056595e5670c9a0f86756da0ad269196e8d56fc1b9fec82 \
|
||||
--hash=sha256:16404e9e404f0b98c18bd752fad812a45ef7f9b0efa9bbc8589f24a94e67de7c
|
||||
certbot-nginx==0.40.1 \
|
||||
--hash=sha256:acdbfc4ab75ebc810264ee1248332f8e857c5e7776717b7cd53c4ceceb2b4d34 \
|
||||
--hash=sha256:014fdda80647ad9e67019b16c7cdaee5d21a750b393bcb98e1300615cc930f4f
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Avoid false warnings because certbot packages are not installed in the thread that executes
|
||||
# the coverage: indeed, certbot is launched as a CLI from a subprocess.
|
||||
disable_warnings = module-not-imported,no-data-collected
|
||||
omit = **/*_test.py,**/tests/*,**/dns_common*,**/certbot_nginx/parser_obj.py
|
||||
|
||||
[report]
|
||||
# Exclude unit tests in coverage during integration tests.
|
||||
|
||||
11
certbot-ci/certbot_integration_tests/assets/hook.py
Executable file
11
certbot-ci/certbot_integration_tests/assets/hook.py
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
|
||||
hook_script_type = os.path.basename(os.path.dirname(sys.argv[1]))
|
||||
if hook_script_type == 'deploy' and ('RENEWED_DOMAINS' not in os.environ or 'RENEWED_LINEAGE' not in os.environ):
|
||||
sys.stderr.write('Environment variables not properly set!\n')
|
||||
sys.exit(1)
|
||||
|
||||
with open(sys.argv[2], 'a') as file_h:
|
||||
file_h.write(hook_script_type + '\n')
|
||||
@@ -1,6 +1,17 @@
|
||||
"""This module contains advanced assertions for the certbot integration tests."""
|
||||
import os
|
||||
import grp
|
||||
try:
|
||||
import grp
|
||||
POSIX_MODE = True
|
||||
except ImportError:
|
||||
import win32api
|
||||
import win32security
|
||||
import ntsecuritycon
|
||||
POSIX_MODE = False
|
||||
|
||||
EVERYBODY_SID = 'S-1-1-0'
|
||||
SYSTEM_SID = 'S-1-5-18'
|
||||
ADMINS_SID = 'S-1-5-32-544'
|
||||
|
||||
|
||||
def assert_hook_execution(probe_path, probe_content):
|
||||
@@ -10,9 +21,10 @@ def assert_hook_execution(probe_path, probe_content):
|
||||
:param probe_content: content expected when the hook is executed
|
||||
"""
|
||||
with open(probe_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
data = file.read()
|
||||
|
||||
assert '{0}{1}'.format(probe_content, os.linesep) in lines
|
||||
lines = [line.strip() for line in data.splitlines()]
|
||||
assert probe_content in lines
|
||||
|
||||
|
||||
def assert_saved_renew_hook(config_dir, lineage):
|
||||
@@ -38,16 +50,51 @@ def assert_cert_count_for_lineage(config_dir, lineage, count):
|
||||
assert len(certs) == count
|
||||
|
||||
|
||||
def assert_equals_permissions(file1, file2, mask):
|
||||
def assert_equals_group_permissions(file1, file2):
|
||||
"""
|
||||
Assert that permissions on two files are identical in respect to a given umask.
|
||||
Assert that two files have the same permissions for group owner.
|
||||
:param file1: first file path to compare
|
||||
:param file2: second file path to compare
|
||||
:param mask: 3-octal representation of a POSIX umask under which the two files mode
|
||||
should match (eg. 0o074 will test RWX on group and R on world)
|
||||
"""
|
||||
mode_file1 = os.stat(file1).st_mode & mask
|
||||
mode_file2 = os.stat(file2).st_mode & mask
|
||||
# On Windows there is no group, so this assertion does nothing on this platform
|
||||
if POSIX_MODE:
|
||||
mode_file1 = os.stat(file1).st_mode & 0o070
|
||||
mode_file2 = os.stat(file2).st_mode & 0o070
|
||||
|
||||
assert mode_file1 == mode_file2
|
||||
|
||||
|
||||
def assert_equals_world_read_permissions(file1, file2):
|
||||
"""
|
||||
Assert that two files have the same read permissions for everyone.
|
||||
:param file1: first file path to compare
|
||||
:param file2: second file path to compare
|
||||
"""
|
||||
if POSIX_MODE:
|
||||
mode_file1 = os.stat(file1).st_mode & 0o004
|
||||
mode_file2 = os.stat(file2).st_mode & 0o004
|
||||
else:
|
||||
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||
|
||||
security1 = win32security.GetFileSecurity(file1, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl1 = security1.GetSecurityDescriptorDacl()
|
||||
|
||||
mode_file1 = dacl1.GetEffectiveRightsFromAcl({
|
||||
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||
'Identifier': everybody,
|
||||
})
|
||||
mode_file1 = mode_file1 & ntsecuritycon.FILE_GENERIC_READ
|
||||
|
||||
security2 = win32security.GetFileSecurity(file2, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl2 = security2.GetSecurityDescriptorDacl()
|
||||
|
||||
mode_file2 = dacl2.GetEffectiveRightsFromAcl({
|
||||
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||
'Identifier': everybody,
|
||||
})
|
||||
mode_file2 = mode_file2 & ntsecuritycon.FILE_GENERIC_READ
|
||||
|
||||
assert mode_file1 == mode_file2
|
||||
|
||||
@@ -57,20 +104,57 @@ def assert_equals_group_owner(file1, file2):
|
||||
Assert that two files have the same group owner.
|
||||
:param file1: first file path to compare
|
||||
:param file2: second file path to compare
|
||||
:return:
|
||||
"""
|
||||
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
|
||||
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
|
||||
# On Windows there is no group, so this assertion does nothing on this platform
|
||||
if POSIX_MODE:
|
||||
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
|
||||
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
|
||||
|
||||
assert group_owner_file1 == group_owner_file2
|
||||
assert group_owner_file1 == group_owner_file2
|
||||
|
||||
|
||||
def assert_world_permissions(file, mode):
|
||||
def assert_world_no_permissions(file):
|
||||
"""
|
||||
Assert that a file has the expected world permission.
|
||||
:param file: file path to check
|
||||
:param mode: world permissions mode expected
|
||||
Assert that the given file is not world-readable.
|
||||
:param file: path of the file to check
|
||||
"""
|
||||
mode_file_all = os.stat(file).st_mode & 0o007
|
||||
if POSIX_MODE:
|
||||
mode_file_all = os.stat(file).st_mode & 0o007
|
||||
assert mode_file_all == 0
|
||||
else:
|
||||
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl = security.GetSecurityDescriptorDacl()
|
||||
mode = dacl.GetEffectiveRightsFromAcl({
|
||||
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
|
||||
})
|
||||
|
||||
assert mode_file_all == mode
|
||||
assert not mode
|
||||
|
||||
|
||||
def assert_world_read_permissions(file):
|
||||
"""
|
||||
Assert that the given file is world-readable, but not world-writable or world-executable.
|
||||
:param file: path of the file to check
|
||||
"""
|
||||
if POSIX_MODE:
|
||||
mode_file_all = os.stat(file).st_mode & 0o007
|
||||
assert mode_file_all == 4
|
||||
else:
|
||||
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl = security.GetSecurityDescriptorDacl()
|
||||
mode = dacl.GetEffectiveRightsFromAcl({
|
||||
'TrusteeForm': win32security.TRUSTEE_IS_SID,
|
||||
'TrusteeType': win32security.TRUSTEE_IS_USER,
|
||||
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
|
||||
})
|
||||
|
||||
assert not mode & ntsecuritycon.FILE_GENERIC_WRITE
|
||||
assert not mode & ntsecuritycon.FILE_GENERIC_EXECUTE
|
||||
assert mode & ntsecuritycon.FILE_GENERIC_READ == ntsecuritycon.FILE_GENERIC_READ
|
||||
|
||||
|
||||
def _get_current_user():
|
||||
account_name = win32api.GetUserNameEx(win32api.NameSamCompatible)
|
||||
return win32security.LookupAccountName(None, account_name)[0]
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""Module to handle the context of integration tests."""
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from certbot_integration_tests.utils import misc, certbot_call
|
||||
from certbot_integration_tests.utils import certbot_call
|
||||
|
||||
|
||||
class IntegrationTestsContext(object):
|
||||
@@ -19,7 +20,7 @@ class IntegrationTestsContext(object):
|
||||
self.worker_id = 'primary'
|
||||
acme_xdist = request.config.acme_xdist
|
||||
|
||||
self.acme_server =acme_xdist['acme_server']
|
||||
self.acme_server = acme_xdist['acme_server']
|
||||
self.directory_url = acme_xdist['directory_url']
|
||||
self.tls_alpn_01_port = acme_xdist['https_port'][self.worker_id]
|
||||
self.http_01_port = acme_xdist['http_port'][self.worker_id]
|
||||
@@ -30,7 +31,10 @@ class IntegrationTestsContext(object):
|
||||
|
||||
self.workspace = tempfile.mkdtemp()
|
||||
self.config_dir = os.path.join(self.workspace, 'conf')
|
||||
self.hook_probe = tempfile.mkstemp(dir=self.workspace)[1]
|
||||
|
||||
probe = tempfile.mkstemp(dir=self.workspace)
|
||||
os.close(probe[0])
|
||||
self.hook_probe = probe[1]
|
||||
|
||||
self.manual_dns_auth_hook = (
|
||||
'{0} -c "import os; import requests; import json; '
|
||||
|
||||
@@ -11,8 +11,11 @@ from os.path import join, exists
|
||||
import pytest
|
||||
from certbot_integration_tests.certbot_tests import context as certbot_context
|
||||
from certbot_integration_tests.certbot_tests.assertions import (
|
||||
assert_hook_execution, assert_saved_renew_hook, assert_cert_count_for_lineage,
|
||||
assert_world_permissions, assert_equals_group_owner, assert_equals_permissions,
|
||||
assert_hook_execution, assert_saved_renew_hook,
|
||||
assert_cert_count_for_lineage,
|
||||
assert_world_no_permissions, assert_world_read_permissions,
|
||||
assert_equals_group_owner, assert_equals_group_permissions, assert_equals_world_read_permissions,
|
||||
EVERYBODY_SID
|
||||
)
|
||||
from certbot_integration_tests.utils import misc
|
||||
|
||||
@@ -84,9 +87,9 @@ def test_http_01(context):
|
||||
context.certbot([
|
||||
'--domains', certname, '--preferred-challenges', 'http-01', 'run',
|
||||
'--cert-name', certname,
|
||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
||||
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
|
||||
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||
'--deploy-hook', misc.echo('deploy', context.hook_probe),
|
||||
])
|
||||
|
||||
assert_hook_execution(context.hook_probe, 'deploy')
|
||||
@@ -104,9 +107,9 @@ def test_manual_http_auth(context):
|
||||
'--cert-name', certname,
|
||||
'--manual-auth-hook', scripts[0],
|
||||
'--manual-cleanup-hook', scripts[1],
|
||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
||||
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
|
||||
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||
'--renew-hook', misc.echo('renew', context.hook_probe),
|
||||
])
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
@@ -122,9 +125,9 @@ def test_manual_dns_auth(context):
|
||||
'run', '--cert-name', certname,
|
||||
'--manual-auth-hook', context.manual_dns_auth_hook,
|
||||
'--manual-cleanup-hook', context.manual_dns_cleanup_hook,
|
||||
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
|
||||
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
|
||||
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
|
||||
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
|
||||
'--post-hook', misc.echo('wtf_post', context.hook_probe),
|
||||
'--renew-hook', misc.echo('renew', context.hook_probe),
|
||||
])
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
@@ -173,21 +176,19 @@ def test_renew_files_permissions(context):
|
||||
certname = context.get_domain('renew')
|
||||
context.certbot(['-d', certname])
|
||||
|
||||
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
|
||||
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
assert_world_permissions(
|
||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0)
|
||||
assert_world_no_permissions(privkey1)
|
||||
|
||||
context.certbot(['renew'])
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
assert_world_permissions(
|
||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0)
|
||||
assert_equals_group_owner(
|
||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'))
|
||||
assert_equals_permissions(
|
||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
|
||||
assert_world_no_permissions(privkey2)
|
||||
assert_equals_group_owner(privkey1, privkey2)
|
||||
assert_equals_world_read_permissions(privkey1, privkey2)
|
||||
assert_equals_group_permissions(privkey1, privkey2)
|
||||
|
||||
|
||||
def test_renew_with_hook_scripts(context):
|
||||
@@ -211,15 +212,35 @@ def test_renew_files_propagate_permissions(context):
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
|
||||
os.chmod(join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0o444)
|
||||
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
|
||||
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
|
||||
|
||||
if os.name != 'nt':
|
||||
os.chmod(privkey1, 0o444)
|
||||
else:
|
||||
import win32security
|
||||
import ntsecuritycon
|
||||
# Get the current DACL of the private key
|
||||
security = win32security.GetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl = security.GetSecurityDescriptorDacl()
|
||||
# Create a read permission for Everybody group
|
||||
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
|
||||
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody)
|
||||
# Apply the updated DACL to the private key
|
||||
security.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||
win32security.SetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION, security)
|
||||
|
||||
context.certbot(['renew'])
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
assert_world_permissions(
|
||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 4)
|
||||
assert_equals_permissions(
|
||||
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
|
||||
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
|
||||
if os.name != 'nt':
|
||||
# On Linux, read world permissions + all group permissions will be copied from the previous private key
|
||||
assert_world_read_permissions(privkey2)
|
||||
assert_equals_world_read_permissions(privkey1, privkey2)
|
||||
assert_equals_group_permissions(privkey1, privkey2)
|
||||
else:
|
||||
# On Windows, world will never have any permissions, and group permission is irrelevant for this platform
|
||||
assert_world_no_permissions(privkey2)
|
||||
|
||||
|
||||
def test_graceful_renew_it_is_not_time(context):
|
||||
@@ -229,7 +250,7 @@ def test_graceful_renew_it_is_not_time(context):
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
|
||||
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
|
||||
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
|
||||
force_renew=False)
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 1)
|
||||
@@ -250,7 +271,7 @@ def test_graceful_renew_it_is_time(context):
|
||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'w') as file:
|
||||
file.writelines(lines)
|
||||
|
||||
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
|
||||
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
|
||||
force_renew=False)
|
||||
|
||||
assert_cert_count_for_lineage(context.config_dir, certname, 2)
|
||||
@@ -317,9 +338,9 @@ def test_renew_hook_override(context):
|
||||
context.certbot([
|
||||
'certonly', '-d', certname,
|
||||
'--preferred-challenges', 'http-01',
|
||||
'--pre-hook', 'echo pre >> "{0}"'.format(context.hook_probe),
|
||||
'--post-hook', 'echo post >> "{0}"'.format(context.hook_probe),
|
||||
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
|
||||
'--pre-hook', misc.echo('pre', context.hook_probe),
|
||||
'--post-hook', misc.echo('post', context.hook_probe),
|
||||
'--deploy-hook', misc.echo('deploy', context.hook_probe),
|
||||
])
|
||||
|
||||
assert_hook_execution(context.hook_probe, 'pre')
|
||||
@@ -330,14 +351,14 @@ def test_renew_hook_override(context):
|
||||
open(context.hook_probe, 'w').close()
|
||||
context.certbot([
|
||||
'renew', '--cert-name', certname,
|
||||
'--pre-hook', 'echo pre-override >> "{0}"'.format(context.hook_probe),
|
||||
'--post-hook', 'echo post-override >> "{0}"'.format(context.hook_probe),
|
||||
'--deploy-hook', 'echo deploy-override >> "{0}"'.format(context.hook_probe)
|
||||
'--pre-hook', misc.echo('pre_override', context.hook_probe),
|
||||
'--post-hook', misc.echo('post_override', context.hook_probe),
|
||||
'--deploy-hook', misc.echo('deploy_override', context.hook_probe),
|
||||
])
|
||||
|
||||
assert_hook_execution(context.hook_probe, 'pre-override')
|
||||
assert_hook_execution(context.hook_probe, 'post-override')
|
||||
assert_hook_execution(context.hook_probe, 'deploy-override')
|
||||
assert_hook_execution(context.hook_probe, 'pre_override')
|
||||
assert_hook_execution(context.hook_probe, 'post_override')
|
||||
assert_hook_execution(context.hook_probe, 'deploy_override')
|
||||
with pytest.raises(AssertionError):
|
||||
assert_hook_execution(context.hook_probe, 'pre')
|
||||
with pytest.raises(AssertionError):
|
||||
@@ -349,11 +370,11 @@ def test_renew_hook_override(context):
|
||||
open(context.hook_probe, 'w').close()
|
||||
context.certbot(['renew', '--cert-name', certname])
|
||||
|
||||
assert_hook_execution(context.hook_probe, 'pre-override')
|
||||
assert_hook_execution(context.hook_probe, 'post-override')
|
||||
assert_hook_execution(context.hook_probe, 'deploy-override')
|
||||
assert_hook_execution(context.hook_probe, 'pre_override')
|
||||
assert_hook_execution(context.hook_probe, 'post_override')
|
||||
assert_hook_execution(context.hook_probe, 'deploy_override')
|
||||
|
||||
|
||||
|
||||
def test_invalid_domain_with_dns_challenge(context):
|
||||
"""Test certificate issuance failure with DNS-01 challenge."""
|
||||
# Manual dns auth hooks from misc are designed to fail if the domain contains 'fail-*'.
|
||||
@@ -512,7 +533,7 @@ def test_revoke_multiple_lineages(context):
|
||||
data = file.read()
|
||||
|
||||
data = re.sub('archive_dir = .*\n',
|
||||
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1)),
|
||||
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1).replace('\\', '\\\\')),
|
||||
data)
|
||||
|
||||
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'w') as file:
|
||||
@@ -555,11 +576,9 @@ def test_ocsp_status_stale(context):
|
||||
|
||||
def test_ocsp_status_live(context):
|
||||
"""Test retrieval of OCSP statuses for live config"""
|
||||
if context.acme_server == 'pebble':
|
||||
pytest.skip('Pebble does not support OCSP status requests.')
|
||||
cert = context.get_domain('ocsp-check')
|
||||
|
||||
# OSCP 1: Check live certificate OCSP status (VALID)
|
||||
cert = context.get_domain('ocsp-check')
|
||||
context.certbot(['--domains', cert])
|
||||
output = context.certbot(['certificates'])
|
||||
|
||||
@@ -575,3 +594,21 @@ def test_ocsp_status_live(context):
|
||||
|
||||
assert output.count('INVALID') == 1, 'Expected {0} to be INVALID'.format(cert)
|
||||
assert output.count('REVOKED') == 1, 'Expected {0} to be REVOKED'.format(cert)
|
||||
|
||||
|
||||
def test_dry_run_deactivate_authzs(context):
|
||||
"""Test that Certbot deactivates authorizations when performing a dry run"""
|
||||
|
||||
name = context.get_domain('dry-run-authz-deactivation')
|
||||
args = ['certonly', '--cert-name', name, '-d', name, '--dry-run']
|
||||
log_line = 'Recreating order after authz deactivation'
|
||||
|
||||
# First order will not need deactivation
|
||||
context.certbot(args)
|
||||
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
|
||||
assert log_line not in f.read(), 'First order should not have had any authz reuse'
|
||||
|
||||
# Second order will require deactivation
|
||||
context.certbot(args)
|
||||
with open(join(context.workspace, 'logs', 'letsencrypt.log'), 'r') as f:
|
||||
assert log_line in f.read(), 'Second order should have been recreated due to authz reuse'
|
||||
|
||||
@@ -125,6 +125,7 @@ class ACMEServer(object):
|
||||
environ = os.environ.copy()
|
||||
environ['PEBBLE_VA_NOSLEEP'] = '1'
|
||||
environ['PEBBLE_WFE_NONCEREJECT'] = '0'
|
||||
environ['PEBBLE_AUTHZREUSE'] = '100'
|
||||
|
||||
self._launch_process(
|
||||
[pebble_path, '-config', pebble_config_path, '-dnsserver', '127.0.0.1:8053'],
|
||||
@@ -134,6 +135,13 @@ class ACMEServer(object):
|
||||
[challtestsrv_path, '-management', ':{0}'.format(CHALLTESTSRV_PORT), '-defaultIPv6', '""',
|
||||
'-defaultIPv4', '127.0.0.1', '-http01', '""', '-tlsalpn01', '""', '-https01', '""'])
|
||||
|
||||
# pebble_ocsp_server is imported here and not at the top of module in order to avoid a useless
|
||||
# ImportError, in the case where cryptography dependency is too old to support ocsp, but
|
||||
# Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is the typical
|
||||
# situation of integration-certbot-oldest tox testenv.
|
||||
from certbot_integration_tests.utils import pebble_ocsp_server
|
||||
self._launch_process([sys.executable, pebble_ocsp_server.__file__])
|
||||
|
||||
# Wait for the ACME CA server to be up.
|
||||
print('=> Waiting for pebble instance to respond...')
|
||||
misc.check_until_timeout(self.acme_xdist['directory_url'])
|
||||
|
||||
@@ -6,7 +6,7 @@ import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
from certbot_integration_tests.utils import misc
|
||||
import certbot_integration_tests
|
||||
from certbot_integration_tests.utils.constants import *
|
||||
|
||||
|
||||
@@ -33,18 +33,58 @@ def certbot_test(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
|
||||
return subprocess.check_output(command, universal_newlines=True, cwd=workspace, env=env)
|
||||
|
||||
|
||||
def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
|
||||
config_dir, workspace, force_renew):
|
||||
def _prepare_environ(workspace):
|
||||
new_environ = os.environ.copy()
|
||||
new_environ['TMPDIR'] = workspace
|
||||
|
||||
# So, pytest is nice, and a little too nice for our usage.
|
||||
# In order to help user to call seamlessly any piece of python code without requiring to
|
||||
# install it as a full-fledged setuptools distribution for instance, it may inject the path
|
||||
# to the test files into the PYTHONPATH. This allows the python interpreter to import
|
||||
# as modules any python file available at this path.
|
||||
# See https://docs.pytest.org/en/3.2.5/pythonpath.html for the explanation and description.
|
||||
# However this behavior is not good in integration tests, in particular the nginx oldest ones.
|
||||
# Indeed during these kind of tests certbot is installed as a transitive dependency to
|
||||
# certbot-nginx. Here is the trick: this certbot version is not necessarily the same as
|
||||
# the certbot codebase lying in current working directory. For instance in oldest tests
|
||||
# certbot==0.36.0 may be installed while the codebase corresponds to certbot==0.37.0.dev0.
|
||||
# Then during a pytest run, PYTHONPATH contains the path to the Certbot codebase, so invoking
|
||||
# certbot will import the modules from the codebase (0.37.0.dev0), not from the
|
||||
# required/installed version (0.36.0).
|
||||
# This will lead to funny and totally incomprehensible errors. To avoid that, we ensure that
|
||||
# if PYTHONPATH is set, it does not contain the path to the root of the codebase.
|
||||
if new_environ.get('PYTHONPATH'):
|
||||
# certbot_integration_tests.__file__ is:
|
||||
# '/path/to/certbot/certbot-ci/certbot_integration_tests/__init__.pyc'
|
||||
# ... and we want '/path/to/certbot'
|
||||
certbot_root = os.path.dirname(os.path.dirname(os.path.dirname(certbot_integration_tests.__file__)))
|
||||
python_paths = [path for path in new_environ['PYTHONPATH'].split(':') if path != certbot_root]
|
||||
new_environ['PYTHONPATH'] = ':'.join(python_paths)
|
||||
|
||||
return new_environ
|
||||
|
||||
|
||||
def _compute_additional_args(workspace, environ, force_renew):
|
||||
additional_args = []
|
||||
if misc.get_certbot_version() >= LooseVersion('0.30.0'):
|
||||
output = subprocess.check_output(['certbot', '--version'],
|
||||
universal_newlines=True, stderr=subprocess.STDOUT,
|
||||
cwd=workspace, env=environ)
|
||||
version_str = output.split(' ')[1].strip() # Typical response is: output = 'certbot 0.31.0.dev0'
|
||||
if LooseVersion(version_str) >= LooseVersion('0.30.0'):
|
||||
additional_args.append('--no-random-sleep-on-renew')
|
||||
|
||||
if force_renew:
|
||||
additional_args.append('--renew-by-default')
|
||||
|
||||
return additional_args
|
||||
|
||||
|
||||
def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_port,
|
||||
config_dir, workspace, force_renew):
|
||||
|
||||
new_environ = _prepare_environ(workspace)
|
||||
additional_args = _compute_additional_args(workspace, new_environ, force_renew)
|
||||
|
||||
command = [
|
||||
'certbot',
|
||||
'--server', directory_url,
|
||||
|
||||
@@ -5,3 +5,5 @@ CHALLTESTSRV_PORT = 8055
|
||||
BOULDER_V1_DIRECTORY_URL = 'http://localhost:4000/directory'
|
||||
BOULDER_V2_DIRECTORY_URL = 'http://localhost:4001/directory'
|
||||
PEBBLE_DIRECTORY_URL = 'https://localhost:14000/dir'
|
||||
PEBBLE_MANAGEMENT_URL = 'https://localhost:15000'
|
||||
MOCK_OCSP_SERVER_PORT = 4002
|
||||
|
||||
@@ -3,9 +3,11 @@ Misc module contains stateless functions that could be used during pytest execut
|
||||
or outside during setup/teardown of the integration tests environment.
|
||||
"""
|
||||
import contextlib
|
||||
import logging
|
||||
import errno
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
@@ -23,7 +25,6 @@ from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
|
||||
from six.moves import socketserver, SimpleHTTPServer
|
||||
|
||||
|
||||
RSA_KEY_TYPE = 'rsa'
|
||||
ECDSA_KEY_TYPE = 'ecdsa'
|
||||
|
||||
@@ -63,6 +64,10 @@ class GracefulTCPServer(socketserver.TCPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
|
||||
def _run_server(port):
|
||||
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def create_http_server(port):
|
||||
"""
|
||||
@@ -75,10 +80,7 @@ def create_http_server(port):
|
||||
current_cwd = os.getcwd()
|
||||
webroot = tempfile.mkdtemp()
|
||||
|
||||
def run():
|
||||
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
|
||||
|
||||
process = multiprocessing.Process(target=run)
|
||||
process = multiprocessing.Process(target=_run_server, args=(port,))
|
||||
|
||||
try:
|
||||
# SimpleHTTPServer is designed to serve files from the current working directory at the
|
||||
@@ -120,15 +122,9 @@ def generate_test_file_hooks(config_dir, hook_probe):
|
||||
:param str config_dir: current certbot config directory
|
||||
:param hook_probe: path to the hook probe to test hook scripts execution
|
||||
"""
|
||||
if sys.platform == 'win32':
|
||||
extension = 'bat'
|
||||
else:
|
||||
extension = 'sh'
|
||||
hook_path = pkg_resources.resource_filename('certbot_integration_tests', 'assets/hook.py')
|
||||
|
||||
renewal_hooks_dirs = list_renewal_hooks_dirs(config_dir)
|
||||
renewal_deploy_hook_path = os.path.join(renewal_hooks_dirs[1], 'hook.sh')
|
||||
|
||||
for hook_dir in renewal_hooks_dirs:
|
||||
for hook_dir in list_renewal_hooks_dirs(config_dir):
|
||||
# We want an equivalent of bash `chmod -p $HOOK_DIR, that does not fail if one folder of
|
||||
# the hierarchy already exists. It is not the case of os.makedirs. Python 3 has an
|
||||
# optional parameter `exists_ok` to not fail on existing dir, but Python 2.7 does not.
|
||||
@@ -138,26 +134,25 @@ def generate_test_file_hooks(config_dir, hook_probe):
|
||||
except OSError as error:
|
||||
if error.errno != errno.EEXIST:
|
||||
raise
|
||||
hook_path = os.path.join(hook_dir, 'hook.{0}'.format(extension))
|
||||
if extension == 'sh':
|
||||
data = '''\
|
||||
#!/bin/bash -xe
|
||||
if [ "$0" = "{0}" ]; then
|
||||
if [ -z "$RENEWED_DOMAINS" -o -z "$RENEWED_LINEAGE" ]; then
|
||||
echo "Environment variables not properly set!" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo $(basename $(dirname "$0")) >> "{1}"\
|
||||
'''.format(renewal_deploy_hook_path, hook_probe)
|
||||
else:
|
||||
# TODO: Write the equivalent bat file for Windows
|
||||
data = '''\
|
||||
|
||||
'''
|
||||
with open(hook_path, 'w') as file:
|
||||
file.write(data)
|
||||
os.chmod(hook_path, os.stat(hook_path).st_mode | stat.S_IEXEC)
|
||||
if os.name != 'nt':
|
||||
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.sh')
|
||||
entrypoint_script = '''\
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
"{0}" "{1}" "{2}" "{3}"
|
||||
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
|
||||
else:
|
||||
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.bat')
|
||||
entrypoint_script = '''\
|
||||
@echo off
|
||||
"{0}" "{1}" "{2}" "{3}"
|
||||
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
|
||||
|
||||
with open(entrypoint_script_path, 'w') as file_h:
|
||||
file_h.write(entrypoint_script)
|
||||
|
||||
os.chmod(entrypoint_script_path, os.stat(entrypoint_script_path).st_mode | stat.S_IEXEC)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
@@ -194,7 +189,7 @@ for _ in range(0, 10):
|
||||
except requests.exceptions.ConnectionError:
|
||||
pass
|
||||
raise ValueError('Error, url did not respond after 10 attempts: {{0}}'.format(url))
|
||||
'''.format(http_server_root, http_port))
|
||||
'''.format(http_server_root.replace('\\', '\\\\'), http_port))
|
||||
os.chmod(auth_script_path, 0o755)
|
||||
|
||||
cleanup_script_path = os.path.join(tempdir, 'cleanup.py')
|
||||
@@ -205,7 +200,7 @@ import os
|
||||
import shutil
|
||||
well_known = os.path.join('{0}', '.well-known')
|
||||
shutil.rmtree(well_known)
|
||||
'''.format(http_server_root))
|
||||
'''.format(http_server_root.replace('\\', '\\\\')))
|
||||
os.chmod(cleanup_script_path, 0o755)
|
||||
|
||||
yield ('{0} {1}'.format(sys.executable, auth_script_path),
|
||||
@@ -214,18 +209,6 @@ shutil.rmtree(well_known)
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
|
||||
def get_certbot_version():
|
||||
"""
|
||||
Find the version of the certbot available in PATH.
|
||||
:return str: the certbot version
|
||||
"""
|
||||
output = subprocess.check_output(['certbot', '--version'],
|
||||
universal_newlines=True, stderr=subprocess.STDOUT)
|
||||
# Typical response is: output = 'certbot 0.31.0.dev0'
|
||||
version_str = output.split(' ')[1].strip()
|
||||
return LooseVersion(version_str)
|
||||
|
||||
|
||||
def generate_csr(domains, key_path, csr_path, key_type=RSA_KEY_TYPE):
|
||||
"""
|
||||
Generate a private key, and a CSR for the given domains using this key.
|
||||
@@ -288,4 +271,32 @@ def load_sample_data_path(workspace):
|
||||
original = pkg_resources.resource_filename('certbot_integration_tests', 'assets/sample-config')
|
||||
copied = os.path.join(workspace, 'sample-config')
|
||||
shutil.copytree(original, copied, symlinks=True)
|
||||
|
||||
if os.name == 'nt':
|
||||
# Fix the symlinks on Windows since GIT is not creating them upon checkout
|
||||
for lineage in ['a.encryption-example.com', 'b.encryption-example.com']:
|
||||
current_live = os.path.join(copied, 'live', lineage)
|
||||
for name in os.listdir(current_live):
|
||||
if name != 'README':
|
||||
current_file = os.path.join(current_live, name)
|
||||
with open(current_file) as file_h:
|
||||
src = file_h.read()
|
||||
os.unlink(current_file)
|
||||
os.symlink(os.path.join(current_live, src), current_file)
|
||||
|
||||
return copied
|
||||
|
||||
|
||||
def echo(keyword, path=None):
|
||||
"""
|
||||
Generate a platform independent executable command
|
||||
that echoes the given keyword into the given file.
|
||||
:param keyword: the keyword to echo (must be a single keyword)
|
||||
:param path: path to the file were keyword is echoed
|
||||
:return: the executable command
|
||||
"""
|
||||
if not re.match(r'^\w+$', keyword):
|
||||
raise ValueError('Error, keyword `{0}` is not a single keyword.'
|
||||
.format(keyword))
|
||||
return '{0} -c "from __future__ import print_function; print(\'{1}\')"{2}'.format(
|
||||
os.path.basename(sys.executable), keyword, ' >> "{0}"'.format(path) if path else '')
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import json
|
||||
import platform
|
||||
import os
|
||||
import stat
|
||||
|
||||
import pkg_resources
|
||||
import requests
|
||||
|
||||
PEBBLE_VERSION = 'v2.1.0'
|
||||
from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT
|
||||
|
||||
PEBBLE_VERSION = 'v2.2.1'
|
||||
ASSETS_PATH = pkg_resources.resource_filename('certbot_integration_tests', 'assets')
|
||||
|
||||
|
||||
def fetch(workspace):
|
||||
suffix = '{0}-{1}{2}'.format(platform.system().lower(),
|
||||
platform.machine().lower().replace('x86_64', 'amd64'),
|
||||
'.exe' if platform.system() == 'Windows' else '')
|
||||
suffix = 'linux-amd64' if os.name != 'nt' else 'windows-amd64.exe'
|
||||
|
||||
pebble_path = _fetch_asset('pebble', suffix)
|
||||
challtestsrv_path = _fetch_asset('pebble-challtestsrv', suffix)
|
||||
@@ -42,10 +41,12 @@ def _build_pebble_config(workspace):
|
||||
file_h.write(json.dumps({
|
||||
'pebble': {
|
||||
'listenAddress': '0.0.0.0:14000',
|
||||
'managementListenAddress': '0.0.0.0:15000',
|
||||
'certificate': os.path.join(ASSETS_PATH, 'cert.pem'),
|
||||
'privateKey': os.path.join(ASSETS_PATH, 'key.pem'),
|
||||
'httpPort': 5002,
|
||||
'tlsPort': 5001,
|
||||
'ocspResponderURL': 'http://127.0.0.1:{0}'.format(MOCK_OCSP_SERVER_PORT),
|
||||
},
|
||||
}))
|
||||
|
||||
|
||||
71
certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py
Executable file
71
certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
This runnable module interfaces itself with the Pebble management interface in order
|
||||
to serve a mock OCSP responder during integration tests against Pebble.
|
||||
"""
|
||||
import datetime
|
||||
import re
|
||||
|
||||
import requests
|
||||
from dateutil import parser
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization, hashes
|
||||
from cryptography import x509
|
||||
from cryptography.x509 import ocsp
|
||||
from six.moves import BaseHTTPServer
|
||||
|
||||
from certbot_integration_tests.utils.misc import GracefulTCPServer
|
||||
from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT, PEBBLE_MANAGEMENT_URL
|
||||
|
||||
|
||||
class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
|
||||
issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())
|
||||
|
||||
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False)
|
||||
issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend())
|
||||
|
||||
try:
|
||||
content_len = int(self.headers.getheader('content-length', 0))
|
||||
except AttributeError:
|
||||
content_len = int(self.headers.get('Content-Length'))
|
||||
|
||||
ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))
|
||||
response = requests.get('{0}/cert-status-by-serial/{1}'.format(
|
||||
PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')), verify=False)
|
||||
|
||||
if not response.ok:
|
||||
ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(ocsp.OCSPResponseStatus.UNAUTHORIZED)
|
||||
else:
|
||||
data = response.json()
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
cert = x509.load_pem_x509_certificate(data['Certificate'].encode(), default_backend())
|
||||
if data['Status'] != 'Revoked':
|
||||
ocsp_status, revocation_time, revocation_reason = ocsp.OCSPCertStatus.GOOD, None, None
|
||||
else:
|
||||
ocsp_status, revocation_reason = ocsp.OCSPCertStatus.REVOKED, x509.ReasonFlags.unspecified
|
||||
revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt']) # "... +0000 UTC" => "+0000"
|
||||
revocation_time = parser.parse(revoked_at)
|
||||
|
||||
ocsp_response = ocsp.OCSPResponseBuilder().add_response(
|
||||
cert=cert, issuer=issuer_cert, algorithm=hashes.SHA1(),
|
||||
cert_status=ocsp_status,
|
||||
this_update=now, next_update=now + datetime.timedelta(hours=1),
|
||||
revocation_time=revocation_time, revocation_reason=revocation_reason
|
||||
).responder_id(
|
||||
ocsp.OCSPResponderEncoding.NAME, issuer_cert
|
||||
).sign(issuer_key, hashes.SHA256())
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
self.wfile.write(ocsp_response.public_bytes(serialization.Encoding.DER))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
GracefulTCPServer(('', MOCK_OCSP_SERVER_PORT), _ProxyHandler).serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
@@ -1,5 +1,7 @@
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
import sys
|
||||
|
||||
from distutils.version import StrictVersion
|
||||
from setuptools import setup, find_packages, __version__ as setuptools_version
|
||||
|
||||
|
||||
version = '0.32.0.dev0'
|
||||
@@ -11,11 +13,23 @@ install_requires = [
|
||||
'pytest',
|
||||
'pytest-cov',
|
||||
'pytest-xdist',
|
||||
'python-dateutil',
|
||||
'pyyaml',
|
||||
'requests',
|
||||
'six',
|
||||
]
|
||||
|
||||
# Add pywin32 on Windows platforms to handle low-level system calls.
|
||||
# This dependency needs to be added using environment markers to avoid its installation on Linux.
|
||||
# However environment markers are supported only with setuptools >= 36.2.
|
||||
# So this dependency is not added for old Linux distributions with old setuptools,
|
||||
# in order to allow these systems to build certbot from sources.
|
||||
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
|
||||
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
|
||||
elif 'bdist_wheel' in sys.argv[1:]:
|
||||
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
|
||||
'of setuptools. Version 36.2+ of setuptools is required.')
|
||||
|
||||
setup(
|
||||
name='certbot-ci',
|
||||
version=version,
|
||||
@@ -37,6 +51,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
],
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCsREbM+UcfsgDy2w56AVGyxsO0HVsbEZHHoEzv7qksIwFgRYMp
|
||||
rowwIxD450RQQqjvw9IoXlMVmr1t5szn5KXn9JRO9T5KNCCy3VPx75WBcp6kzd9Q
|
||||
2HS1OEOtpilNnDkZ+TJfdgFWPUBYj2o4Md1hPmcvagiIJY5U6speka2bjwIDAQAB
|
||||
AoGANCMZ9pF/mDUsmlP4Rq69hkkoFAxKdZ/UqkF256so4mXZ1cRUFTpxzWPfkCWW
|
||||
hGAYdzCiG3uo08IYkPmojIqkN1dk5Hcq5eQAmshaPkQHQCHjmPjjcNvgjIXQoGUf
|
||||
TpDU2hbY4UAlJlj4ZLh+jGP5Zq8/WrNi8RsI3v9Nagfp/FECQQDgi2q8p1gX0TNh
|
||||
d1aEKmSXkR3bxkyFk6oS+pBrAG3+yX27ZayN6Rx6DOs/FcBsOu7fX3PYBziDeEWe
|
||||
Lkf1P743AkEAxGYT/LY3puglSz4iJZZzWmRCrVOg41yhfQ+F1BRX43/2vtoU5GyM
|
||||
2lUn1vQ2e/rfmnAvfJxc90GeZCIHB1ihaQJBALH8UMLxMtbOMJgVbDKfF9U8ZhqK
|
||||
+KT5A1q/2jG2yXmoZU1hroFeQgBMtTvwFfK0VBwjIUQflSBA+Y4EyW0Q9ckCQGvd
|
||||
jHitM1+N/H2YwHRYbz5j9mLvnVuCEod3MQ9LpQGj1Eb5y6OxIqL/RgQ+2HW7UXem
|
||||
yc3sqvp5pZ5lOesE+JECQETPI64gqxlTIs3nErNMpMynUuTWpaElOcIJTT6icLzB
|
||||
Xix67kKXjROO5D58GEYkM0Yi5k7YdUPoQBW7MoIrSIA=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -1,15 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQDCzejLjo8wsz0avrylt7HQyF0+vsKritF70EGmc64cV0XfkCTR
|
||||
o+vMXBXMuUY6Kv3hTXV7klgkNYmL7gXAsFGQ4B9qeMnkYn0GcQdI51u076y/26Fu
|
||||
37uJg45Q6eApKInJSsyLVMcAT4HUJ6fFnUodFAKR7vTzOQryNW7Et4gA4wIDAQAB
|
||||
AoGAKiAU40/krwdTg2ETslJS5W8ums7tkeLnAfs69x+02vQUbA/jpmHoL70KCcdW
|
||||
5GU/mWUCrsIqxUm+gL/sBosaV/TF256qUBt2qQCZTN8MbDaNSYiiMnucOfbWdIqx
|
||||
Zgls6GUoXQvPic9RUoFSlgfSjo5ezz6el5ihvRMp+wbk24ECQQD3oz4hN029DSZo
|
||||
Y3+flmBn77gA0BMUvLa6hmt9b3xT5U/ToCLfbmUvpx7zV1g5era2y9qt/o3UtAbW
|
||||
1zCVETgzAkEAyWHv/+RnSXp8/D4YwTVWyeWi862uNBPkuLGP/0zASdwBfBK3uBls
|
||||
+VumfSCtp0kt2AXXmScg1fkHdeAVT6AkkQJBAJb2XRnCrRFiwtdAULzo3zx9Vp6o
|
||||
OfmaUYrEByMgo5pBYLiSFrA+jFDQgH238YCY3mnxPA517+CLHuA5rtQw+yECQCfm
|
||||
gL/pyFE1tLfhsdPuNpDwL9YqLl7hJis1+zrxQRQhRCYKK16NoxrQ/u7B38ZKaIvp
|
||||
tGsC5q2elszTJkXNjBECQCVE9QCVx056vHVdPWM8z3GAeV3sJQ01HLLjebTEEz6G
|
||||
jH54gk+YYPp4kjCvVUykbnB58BY2n88GQt5Jj5eLuMo=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -8,13 +8,13 @@ import tarfile
|
||||
|
||||
import josepy as jose
|
||||
|
||||
from acme import test_util
|
||||
from certbot.tests import util as test_util
|
||||
from certbot import constants
|
||||
|
||||
from certbot_compatibility_test import errors
|
||||
|
||||
|
||||
_KEY_BASE = "rsa1024_key.pem"
|
||||
_KEY_BASE = "rsa2048_key.pem"
|
||||
KEY_PATH = test_util.vector_path(_KEY_BASE)
|
||||
KEY = test_util.load_pyopenssl_private_key(_KEY_BASE)
|
||||
JWK = jose.JWKRSA(key=test_util.load_rsa_private_key(_KEY_BASE))
|
||||
|
||||
@@ -4,7 +4,7 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
install_requires = [
|
||||
'certbot',
|
||||
@@ -47,6 +47,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
],
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'cloudflare>=1.5.1',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'mock',
|
||||
'python-digitalocean>=1.11',
|
||||
'setuptools',
|
||||
@@ -44,6 +44,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -3,13 +3,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'mock',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
@@ -55,6 +55,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,12 +2,12 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.1.22',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -41,6 +41,8 @@ setup(
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,18 +2,16 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0',
|
||||
# 1.5 is the first version that supports oauth2client>=2.0
|
||||
'google-api-python-client>=1.5',
|
||||
'certbot>=0.39.0',
|
||||
'google-api-python-client>=1.5.5',
|
||||
'mock',
|
||||
# for oauth2client.service_account.ServiceAccountCredentials
|
||||
'oauth2client>=2.0',
|
||||
'oauth2client>=4.0',
|
||||
'setuptools',
|
||||
'zope.interface',
|
||||
# already a dependency of google-api-python-client, but added for consistency
|
||||
@@ -48,6 +46,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
dns-lexicon==2.2.3
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.2.3',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -41,6 +41,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
dns-lexicon==2.7.14
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -42,6 +42,8 @@ setup(
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,13 +2,13 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dnspython',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -43,6 +43,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.29.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||
# acme/certbot version.
|
||||
install_requires = [
|
||||
'acme>=0.29.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'boto3',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -37,6 +37,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Remember to update setup.py to match the package versions below.
|
||||
acme[dev]==0.31.0
|
||||
certbot[dev]==0.34.0
|
||||
certbot[dev]==0.39.0
|
||||
|
||||
@@ -2,12 +2,12 @@ from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
|
||||
version = '0.37.0.dev0'
|
||||
version = '1.0.0.dev0'
|
||||
|
||||
# Please update tox.ini when modifying dependency version requirements
|
||||
install_requires = [
|
||||
'acme>=0.31.0',
|
||||
'certbot>=0.34.0',
|
||||
'certbot>=0.39.0',
|
||||
'dns-lexicon>=2.1.23',
|
||||
'mock',
|
||||
'setuptools',
|
||||
@@ -41,6 +41,8 @@ setup(
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Security',
|
||||
'Topic :: System :: Installation/Setup',
|
||||
|
||||
@@ -2,5 +2,4 @@ include LICENSE.txt
|
||||
include README.rst
|
||||
recursive-include docs *
|
||||
recursive-include certbot_nginx/tests/testdata *
|
||||
include certbot_nginx/options-ssl-nginx.conf
|
||||
include certbot_nginx/options-ssl-nginx-old.conf
|
||||
recursive-include certbot_nginx/tls_configs *.conf
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
"""Nginx Configuration"""
|
||||
# https://github.com/PyCQA/pylint/issues/73
|
||||
from distutils.version import LooseVersion # pylint: disable=no-name-in-module,import-error
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
@@ -91,8 +93,12 @@ class NginxConfigurator(common.Installer):
|
||||
:param tup version: version of Nginx as a tuple (1, 4, 7)
|
||||
(used mostly for unittesting)
|
||||
|
||||
:param tup openssl_version: version of OpenSSL linked to Nginx as a tuple (1, 4, 7)
|
||||
(used mostly for unittesting)
|
||||
|
||||
"""
|
||||
version = kwargs.pop("version", None)
|
||||
openssl_version = kwargs.pop("openssl_version", None)
|
||||
super(NginxConfigurator, self).__init__(*args, **kwargs)
|
||||
|
||||
# Verify that all directories and files exist with proper permissions
|
||||
@@ -115,6 +121,7 @@ class NginxConfigurator(common.Installer):
|
||||
# These will be set in the prepare function
|
||||
self.parser = None
|
||||
self.version = version
|
||||
self.openssl_version = openssl_version
|
||||
self._enhance_func = {"redirect": self._enable_redirect,
|
||||
"ensure-http-header": self._set_http_header,
|
||||
"staple-ocsp": self._enable_ocsp_stapling}
|
||||
@@ -124,10 +131,35 @@ class NginxConfigurator(common.Installer):
|
||||
@property
|
||||
def mod_ssl_conf_src(self):
|
||||
"""Full absolute path to SSL configuration file source."""
|
||||
config_filename = "options-ssl-nginx.conf"
|
||||
if self.version < (1, 5, 9):
|
||||
config_filename = "options-ssl-nginx-old.conf"
|
||||
return pkg_resources.resource_filename("certbot_nginx", config_filename)
|
||||
|
||||
# Why all this complexity? Well, we want to support Mozilla's intermediate
|
||||
# recommendations. But TLS1.3 is only supported by newer versions of Nginx.
|
||||
# And as for session tickets, our ideal is to turn them off across the board.
|
||||
# But! Turning them off at all is only supported with new enough versions of
|
||||
# Nginx. And older versions of OpenSSL have a bug that leads to browser errors
|
||||
# given certain configurations. While we'd prefer to have forward secrecy, we'd
|
||||
# rather fail open than error out. Unfortunately, Nginx can be compiled against
|
||||
# many versions of OpenSSL. So we have to check both for the two different features,
|
||||
# leading to four different combinations of options.
|
||||
# For a complete history, check out https://github.com/certbot/certbot/issues/7322
|
||||
|
||||
use_tls13 = self.version >= (1, 13, 0)
|
||||
session_tix_off = self.version >= (1, 5, 9) and self.openssl_version and\
|
||||
LooseVersion(self.openssl_version) >= LooseVersion('1.0.2l')
|
||||
|
||||
if use_tls13:
|
||||
if session_tix_off:
|
||||
config_filename = "options-ssl-nginx.conf"
|
||||
else:
|
||||
config_filename = "options-ssl-nginx-tls13-session-tix-on.conf"
|
||||
else:
|
||||
if session_tix_off:
|
||||
config_filename = "options-ssl-nginx-tls12-only.conf"
|
||||
else:
|
||||
config_filename = "options-ssl-nginx-old.conf"
|
||||
|
||||
return pkg_resources.resource_filename(
|
||||
"certbot_nginx", os.path.join("tls_configs", config_filename))
|
||||
|
||||
@property
|
||||
def mod_ssl_conf(self):
|
||||
@@ -166,6 +198,9 @@ class NginxConfigurator(common.Installer):
|
||||
if self.version is None:
|
||||
self.version = self.get_version()
|
||||
|
||||
if self.openssl_version is None:
|
||||
self.openssl_version = self._get_openssl_version()
|
||||
|
||||
self.install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
|
||||
|
||||
self.install_ssl_dhparams()
|
||||
@@ -906,17 +941,14 @@ class NginxConfigurator(common.Installer):
|
||||
util.make_or_verify_dir(self.config.backup_dir, core_constants.CONFIG_DIRS_MODE)
|
||||
util.make_or_verify_dir(self.config.config_dir, core_constants.CONFIG_DIRS_MODE)
|
||||
|
||||
def get_version(self):
|
||||
"""Return version of Nginx Server.
|
||||
def _nginx_version(self):
|
||||
"""Return results of nginx -V
|
||||
|
||||
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
|
||||
|
||||
:returns: version
|
||||
:rtype: tuple
|
||||
:returns: version text
|
||||
:rtype: str
|
||||
|
||||
:raises .PluginError:
|
||||
Unable to find Nginx version or version is unsupported
|
||||
|
||||
Unable to run Nginx version command
|
||||
"""
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
@@ -929,6 +961,21 @@ class NginxConfigurator(common.Installer):
|
||||
logger.debug(str(error), exc_info=True)
|
||||
raise errors.PluginError(
|
||||
"Unable to run %s -V" % self.conf('ctl'))
|
||||
return text
|
||||
|
||||
def get_version(self):
|
||||
"""Return version of Nginx Server.
|
||||
|
||||
Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))
|
||||
|
||||
:returns: version
|
||||
:rtype: tuple
|
||||
|
||||
:raises .PluginError:
|
||||
Unable to find Nginx version or version is unsupported
|
||||
|
||||
"""
|
||||
text = self._nginx_version()
|
||||
|
||||
version_regex = re.compile(r"nginx version: ([^/]+)/([0-9\.]*)", re.IGNORECASE)
|
||||
version_matches = version_regex.findall(text)
|
||||
@@ -961,6 +1008,28 @@ class NginxConfigurator(common.Installer):
|
||||
|
||||
return nginx_version
|
||||
|
||||
def _get_openssl_version(self):
|
||||
"""Return version of OpenSSL linked to Nginx.
|
||||
|
||||
Version is returned as string. If no version can be found, empty string is returned.
|
||||
|
||||
:returns: openssl_version
|
||||
:rtype: str
|
||||
|
||||
:raises .PluginError:
|
||||
Unable to run Nginx version command
|
||||
"""
|
||||
text = self._nginx_version()
|
||||
|
||||
matches = re.findall(r"running with OpenSSL ([^ ]+) ", text)
|
||||
if not matches:
|
||||
matches = re.findall(r"built with OpenSSL ([^ ]+) ", text)
|
||||
if not matches:
|
||||
logger.warning("NGINX configured with OpenSSL alternatives is not officially"
|
||||
"supported by Certbot.")
|
||||
return ""
|
||||
return matches[0]
|
||||
|
||||
def more_info(self):
|
||||
"""Human-readable string to help understand the module"""
|
||||
return (
|
||||
@@ -1038,7 +1107,7 @@ class NginxConfigurator(common.Installer):
|
||||
###########################################################################
|
||||
def get_chall_pref(self, unused_domain): # pylint: disable=no-self-use
|
||||
"""Return list of challenge preferences."""
|
||||
return [challenges.HTTP01, challenges.TLSSNI01]
|
||||
return [challenges.HTTP01]
|
||||
|
||||
# Entry point in main.py for performing challenges
|
||||
def perform(self, achalls):
|
||||
|
||||
@@ -22,12 +22,6 @@ MOD_SSL_CONF_DEST = "options-ssl-nginx.conf"
|
||||
UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
|
||||
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
|
||||
|
||||
SSL_OPTIONS_HASHES_NEW = [
|
||||
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
|
||||
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
|
||||
]
|
||||
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9"""
|
||||
|
||||
ALL_SSL_OPTIONS_HASHES = [
|
||||
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
|
||||
'9a7b32c49001fed4cff8ad24353329472a50e86ade1ef9b2b9e43566a619612e',
|
||||
@@ -36,7 +30,18 @@ ALL_SSL_OPTIONS_HASHES = [
|
||||
'394732f2bbe3e5e637c3fb5c6e980a1f1b90b01e2e8d6b7cff41dde16e2a756d',
|
||||
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
|
||||
'c052ffff0ad683f43bffe105f7c606b339536163490930e2632a335c8d191cc4',
|
||||
] + SSL_OPTIONS_HASHES_NEW
|
||||
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
|
||||
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
|
||||
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
|
||||
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
|
||||
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
|
||||
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
|
||||
'd5e021706ecdccc7090111b0ae9a29ef61523e927f020e410caf0a1fd7063981',
|
||||
'ef11e3fb17213e74d3e1816cde0ec37b8b95b4167cf21e7b8ff1eaa9c6f918ee',
|
||||
'af85f6193808a44789a1d293e6cffa249cad9a21135940800958b8e3c72dbc69',
|
||||
'a2a612fd21b02abaa32d9d11ac63d987d6e3054dbfa356de5800eea0d7ce17f3',
|
||||
'2d9648302e3588a172c318e46bff88ade46fc7a16d6afc85322776a04800d473',
|
||||
]
|
||||
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
|
||||
|
||||
def os_constant(key):
|
||||
|
||||
@@ -29,10 +29,10 @@ class NginxHttp01(common.ChallengePerformer):
|
||||
:param list indices: Meant to hold indices of challenges in a
|
||||
larger array. NginxHttp01 is capable of solving many challenges
|
||||
at once which causes an indexing issue within NginxConfigurator
|
||||
who must return all responses in order. Imagine NginxConfigurator
|
||||
maintaining state about where all of the http-01 Challenges,
|
||||
TLS-SNI-01 Challenges belong in the response array. This is an
|
||||
optional utility.
|
||||
who must return all responses in order. Imagine
|
||||
NginxConfigurator maintaining state about where all of the
|
||||
challenges, possibly of different types, belong in the response
|
||||
array. This is an optional utility.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
|
||||
@@ -1,14 +0,0 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
|
||||
@@ -97,7 +97,7 @@ class NginxConfiguratorTest(util.NginxTest):
|
||||
errors.PluginError, self.config.enhance, 'myhost', 'unknown_enhancement')
|
||||
|
||||
def test_get_chall_pref(self):
|
||||
self.assertEqual([challenges.HTTP01, challenges.TLSSNI01],
|
||||
self.assertEqual([challenges.HTTP01],
|
||||
self.config.get_chall_pref('myhost'))
|
||||
|
||||
def test_save(self):
|
||||
@@ -394,6 +394,68 @@ class NginxConfiguratorTest(util.NginxTest):
|
||||
mock_popen.side_effect = OSError("Can't find program")
|
||||
self.assertRaises(errors.PluginError, self.config.get_version)
|
||||
|
||||
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
|
||||
def test_get_openssl_version(self, mock_popen):
|
||||
# pylint: disable=protected-access
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
built with OpenSSL 1.0.2g 1 Mar 2016
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "1.0.2g")
|
||||
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
built with OpenSSL 1.0.2-beta1 1 Mar 2016
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "1.0.2-beta1")
|
||||
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
built with OpenSSL 1.0.2 1 Mar 2016
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "1.0.2")
|
||||
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
built with OpenSSL 1.0.2g 1 Mar 2016 (running with OpenSSL 1.0.2a 1 Mar 2016)
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "1.0.2a")
|
||||
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
built with LibreSSL 2.2.2
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "")
|
||||
|
||||
mock_popen().communicate.return_value = (
|
||||
"", """
|
||||
nginx version: nginx/1.15.5
|
||||
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
|
||||
TLS SNI support enabled
|
||||
configure arguments:
|
||||
""")
|
||||
self.assertEqual(self.config._get_openssl_version(), "")
|
||||
|
||||
@mock.patch("certbot_nginx.configurator.subprocess.Popen")
|
||||
def test_nginx_restart(self, mock_popen):
|
||||
mocked = mock_popen()
|
||||
@@ -920,13 +982,12 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
||||
self._assert_current_file()
|
||||
|
||||
def test_prev_file_updates_to_current_old_nginx(self):
|
||||
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES, SSL_OPTIONS_HASHES_NEW
|
||||
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
|
||||
self.config.version = (1, 5, 8)
|
||||
with mock.patch('certbot.crypto_util.sha256sum',
|
||||
new=self._mock_hash_except_ssl_conf_src(ALL_SSL_OPTIONS_HASHES[0])):
|
||||
self._call()
|
||||
self._assert_current_file()
|
||||
self.assertTrue(self._current_ssl_options_hash() not in SSL_OPTIONS_HASHES_NEW)
|
||||
|
||||
def test_manually_modified_current_file_does_not_update(self):
|
||||
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
|
||||
@@ -963,15 +1024,50 @@ class InstallSslOptionsConfTest(util.NginxTest):
|
||||
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
|
||||
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
|
||||
|
||||
def test_old_nginx_version_uses_old_config(self):
|
||||
def test_ssl_config_files_hash_in_all_hashes(self):
|
||||
"""
|
||||
It is really critical that all TLS Nginx config files have their SHA256 hash registered in
|
||||
constants.ALL_SSL_OPTIONS_HASHES. Otherwise Certbot will mistakenly assume that the config
|
||||
file has been manually edited by the user, and will refuse to update it.
|
||||
This test ensures that all necessary hashes are present.
|
||||
"""
|
||||
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
|
||||
import pkg_resources
|
||||
all_files = [
|
||||
pkg_resources.resource_filename("certbot_nginx", os.path.join("tls_configs", x))
|
||||
for x in ("options-ssl-nginx.conf",
|
||||
"options-ssl-nginx-old.conf",
|
||||
"options-ssl-nginx-tls12-only.conf")
|
||||
]
|
||||
self.assertTrue(all_files)
|
||||
for one_file in all_files:
|
||||
file_hash = crypto_util.sha256sum(one_file)
|
||||
self.assertTrue(file_hash in ALL_SSL_OPTIONS_HASHES,
|
||||
"Constants.ALL_SSL_OPTIONS_HASHES must be appended with the sha256 "
|
||||
"hash of {0} when it is updated.".format(one_file))
|
||||
|
||||
def test_nginx_version_uses_correct_config(self):
|
||||
self.config.version = (1, 5, 8)
|
||||
self.config.openssl_version = "1.0.2g" # shouldn't matter
|
||||
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||
"options-ssl-nginx-old.conf")
|
||||
self._call()
|
||||
self._assert_current_file()
|
||||
self.config.version = (1, 5, 9)
|
||||
self.config.openssl_version = "1.0.2l"
|
||||
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||
"options-ssl-nginx-tls12-only.conf")
|
||||
self._call()
|
||||
self._assert_current_file()
|
||||
self.config.version = (1, 13, 0)
|
||||
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||
"options-ssl-nginx.conf")
|
||||
self._call()
|
||||
self._assert_current_file()
|
||||
self.config.version = (1, 13, 0)
|
||||
self.config.openssl_version = "1.0.2k"
|
||||
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
|
||||
"options-ssl-nginx-tls13-session-tix-on.conf")
|
||||
|
||||
|
||||
class DetermineDefaultServerRootTest(certbot_test_util.ConfigTestCase):
|
||||
|
||||
@@ -73,11 +73,11 @@ class HttpPerformTest(util.NginxTest):
|
||||
self.http01.add_chall(achall)
|
||||
acme_responses.append(achall.response(self.account_key))
|
||||
|
||||
sni_responses = self.http01.perform()
|
||||
http_responses = self.http01.perform()
|
||||
|
||||
self.assertEqual(len(sni_responses), 4)
|
||||
self.assertEqual(len(http_responses), 4)
|
||||
for i in six.moves.range(4):
|
||||
self.assertEqual(sni_responses[i], acme_responses[i])
|
||||
self.assertEqual(http_responses[i], acme_responses[i])
|
||||
|
||||
def test_mod_config(self):
|
||||
self.http01.add_chall(self.achalls[0])
|
||||
|
||||
@@ -30,8 +30,16 @@ class NginxParserTest(util.NginxTest): #pylint: disable=too-many-public-methods
|
||||
self.assertEqual(nparser.root, self.config_path)
|
||||
|
||||
def test_root_absolute(self):
|
||||
nparser = parser.NginxParser(os.path.relpath(self.config_path))
|
||||
self.assertEqual(nparser.root, self.config_path)
|
||||
curr_dir = os.getcwd()
|
||||
try:
|
||||
# On Windows current directory may be on a different drive than self.tempdir.
|
||||
# However a relative path between two different drives is invalid. So we move to
|
||||
# self.tempdir to ensure that we stay on the same drive.
|
||||
os.chdir(self.temp_dir)
|
||||
nparser = parser.NginxParser(os.path.relpath(self.config_path))
|
||||
self.assertEqual(nparser.root, self.config_path)
|
||||
finally:
|
||||
os.chdir(curr_dir)
|
||||
|
||||
def test_root_no_trailing_slash(self):
|
||||
nparser = parser.NginxParser(self.config_path + os.path.sep)
|
||||
|
||||
@@ -3,7 +3,6 @@ import copy
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
import josepy as jose
|
||||
import mock
|
||||
@@ -11,6 +10,7 @@ import pkg_resources
|
||||
import zope.component
|
||||
|
||||
from certbot import configuration
|
||||
from certbot import util
|
||||
from certbot.compat import os
|
||||
from certbot.plugins import common
|
||||
from certbot.tests import util as test_util
|
||||
@@ -34,20 +34,16 @@ class NginxTest(unittest.TestCase): # pylint: disable=too-few-public-methods
|
||||
"rsa512_key.pem"))
|
||||
|
||||
def tearDown(self):
|
||||
# On Windows we have various files which are not correctly closed at the time of tearDown.
|
||||
# For know, we log them until a proper file close handling is written.
|
||||
# Useful for development only, so no warning when we are on a CI process.
|
||||
def onerror_handler(_, path, excinfo):
|
||||
"""On error handler"""
|
||||
if not os.environ.get('APPVEYOR'): # pragma: no cover
|
||||
message = ('Following error occurred when deleting path {0}'
|
||||
'during tearDown process: {1}'.format(path, str(excinfo)))
|
||||
warnings.warn(message)
|
||||
# Cleanup opened resources after a test. This is usually done through atexit handlers in
|
||||
# Certbot, but during tests, atexit will not run registered functions before tearDown is
|
||||
# called and instead will run them right before the entire test process exits.
|
||||
# It is a problem on Windows, that does not accept to clean resources before closing them.
|
||||
util._release_locks() # pylint: disable=protected-access
|
||||
|
||||
shutil.rmtree(self.temp_dir, onerror=onerror_handler)
|
||||
shutil.rmtree(self.config_dir, onerror=onerror_handler)
|
||||
shutil.rmtree(self.work_dir, onerror=onerror_handler)
|
||||
shutil.rmtree(self.logs_dir, onerror=onerror_handler)
|
||||
shutil.rmtree(self.temp_dir)
|
||||
shutil.rmtree(self.config_dir)
|
||||
shutil.rmtree(self.work_dir)
|
||||
shutil.rmtree(self.logs_dir)
|
||||
|
||||
|
||||
def get_data_filename(filename):
|
||||
@@ -58,7 +54,7 @@ def get_data_filename(filename):
|
||||
|
||||
|
||||
def get_nginx_configurator(
|
||||
config_path, config_dir, work_dir, logs_dir, version=(1, 6, 2)):
|
||||
config_path, config_dir, work_dir, logs_dir, version=(1, 6, 2), openssl_version="1.0.2g"):
|
||||
"""Create an Nginx Configurator with the specified options."""
|
||||
|
||||
backups = os.path.join(work_dir, "backups")
|
||||
@@ -83,7 +79,8 @@ def get_nginx_configurator(
|
||||
https_port=5001,
|
||||
),
|
||||
name="nginx",
|
||||
version=version)
|
||||
version=version,
|
||||
openssl_version=openssl_version)
|
||||
config.prepare()
|
||||
|
||||
# Provide general config utility.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
|
||||
ssl_protocols TLSv1.2;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
|
||||
@@ -0,0 +1,14 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1.2;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
|
||||
@@ -0,0 +1,14 @@
|
||||
# This file contains important security parameters. If you modify this file
|
||||
# manually, Certbot will be unable to automatically provide future security
|
||||
# updates. Instead, Certbot will print and log an error message with a path to
|
||||
# the up-to-date file that you will need to refer to when manually updating
|
||||
# this file.
|
||||
|
||||
ssl_session_cache shared:le_nginx_SSL:10m;
|
||||
ssl_session_timeout 1440m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user