forked from TrueCloudLab/lego
42941ccea6
- Packages - Isolate code used by the CLI into the package `cmd` - (experimental) Add e2e tests for HTTP01, TLS-ALPN-01 and DNS-01, use [Pebble](https://github.com/letsencrypt/pebble) and [challtestsrv](https://github.com/letsencrypt/boulder/tree/master/test/challtestsrv) - Support non-ascii domain name (punnycode) - Check all challenges in a predictable order - No more global exported variables - Archive revoked certificates - Fixes revocation for subdomains and non-ascii domains - Disable pending authorizations - use pointer for RemoteError/ProblemDetails - Poll authz URL instead of challenge URL - The ability for a DNS provider to solve the challenge sequentially - Check all nameservers in a predictable order - Option to disable the complete propagation Requirement - CLI, support for renew with CSR - CLI, add SAN on renew - Add command to list certificates. - Logs every iteration of waiting for the propagation - update DNSimple client - update github.com/miekg/dns
344 lines
8.5 KiB
Go
344 lines
8.5 KiB
Go
package e2e
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/xenolf/lego/certificate"
|
|
"github.com/xenolf/lego/challenge"
|
|
"github.com/xenolf/lego/e2e/loader"
|
|
"github.com/xenolf/lego/lego"
|
|
"github.com/xenolf/lego/registration"
|
|
)
|
|
|
|
var load = loader.EnvLoader{
|
|
PebbleOptions: &loader.CmdOption{
|
|
HealthCheckURL: "https://localhost:14000/dir",
|
|
Args: []string{"-strict", "-config", "fixtures/pebble-config.json"},
|
|
Env: []string{"PEBBLE_VA_NOSLEEP=1", "PEBBLE_WFE_NONCEREJECT=20"},
|
|
},
|
|
LegoOptions: []string{
|
|
"LEGO_CA_CERTIFICATES=./fixtures/certs/pebble.minica.pem",
|
|
},
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
os.Exit(load.MainTest(m))
|
|
}
|
|
|
|
func TestHelp(t *testing.T) {
|
|
output, err := load.RunLego("-h")
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s\n", output)
|
|
t.Fatal(err)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
|
|
func TestChallengeHTTP_Run(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "tls-alpn-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "acme.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeTLS_Run_Domains(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "acme.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeTLS_Run_CSR(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-csr", "./fixtures/csr.raw",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeTLS_Run_CSR_PEM(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-csr", "./fixtures/csr.cert",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeTLS_Run_Revoke(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "lego.wtf",
|
|
"-d", "acme.lego.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
output, err = load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "lego.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"revoke")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeTLS_Run_Revoke_Non_ASCII(t *testing.T) {
|
|
loader.CleanLegoFiles()
|
|
|
|
output, err := load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "légô.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"run")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
output, err = load.RunLego(
|
|
"-m", "hubert@hubert.com",
|
|
"--accept-tos",
|
|
"-x", "dns-01",
|
|
"-x", "http-01",
|
|
"-s", "https://localhost:14000/dir",
|
|
"-d", "légô.wtf",
|
|
"--http", ":5002",
|
|
"--tls", ":5001",
|
|
"revoke")
|
|
|
|
if len(output) > 0 {
|
|
fmt.Fprintf(os.Stdout, "%s\n", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestChallengeHTTP_Client_Obtain(t *testing.T) {
|
|
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
|
require.NoError(t, err)
|
|
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
|
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
require.NoError(t, err, "Could not generate test key")
|
|
|
|
user := &fakeUser{privateKey: privateKey}
|
|
config := lego.NewConfig(user)
|
|
config.CADirURL = load.PebbleOptions.HealthCheckURL
|
|
|
|
client, err := lego.NewClient(config)
|
|
require.NoError(t, err)
|
|
|
|
client.Challenge.Exclude([]challenge.Type{challenge.DNS01, challenge.TLSALPN01})
|
|
err = client.Challenge.SetHTTP01Address(":5002")
|
|
require.NoError(t, err)
|
|
|
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
require.NoError(t, err)
|
|
user.registration = reg
|
|
|
|
request := certificate.ObtainRequest{
|
|
Domains: []string{"acme.wtf"},
|
|
Bundle: true,
|
|
}
|
|
resource, err := client.Certificate.Obtain(request)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, resource)
|
|
assert.Equal(t, "acme.wtf", resource.Domain)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
|
|
assert.NotEmpty(t, resource.Certificate)
|
|
assert.NotEmpty(t, resource.IssuerCertificate)
|
|
assert.Empty(t, resource.CSR)
|
|
}
|
|
|
|
func TestChallengeTLS_Client_Obtain(t *testing.T) {
|
|
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
|
require.NoError(t, err)
|
|
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
|
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
require.NoError(t, err, "Could not generate test key")
|
|
|
|
user := &fakeUser{privateKey: privateKey}
|
|
config := lego.NewConfig(user)
|
|
config.CADirURL = load.PebbleOptions.HealthCheckURL
|
|
|
|
client, err := lego.NewClient(config)
|
|
require.NoError(t, err)
|
|
|
|
client.Challenge.Exclude([]challenge.Type{challenge.DNS01, challenge.HTTP01})
|
|
err = client.Challenge.SetTLSALPN01Address(":5001")
|
|
require.NoError(t, err)
|
|
|
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
require.NoError(t, err)
|
|
user.registration = reg
|
|
|
|
request := certificate.ObtainRequest{
|
|
Domains: []string{"acme.wtf"},
|
|
Bundle: true,
|
|
PrivateKey: privateKey,
|
|
}
|
|
resource, err := client.Certificate.Obtain(request)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, resource)
|
|
assert.Equal(t, "acme.wtf", resource.Domain)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
|
|
assert.NotEmpty(t, resource.Certificate)
|
|
assert.NotEmpty(t, resource.IssuerCertificate)
|
|
assert.Empty(t, resource.CSR)
|
|
}
|
|
|
|
func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
|
|
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
|
|
require.NoError(t, err)
|
|
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
|
|
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
require.NoError(t, err, "Could not generate test key")
|
|
|
|
user := &fakeUser{privateKey: privateKey}
|
|
config := lego.NewConfig(user)
|
|
config.CADirURL = load.PebbleOptions.HealthCheckURL
|
|
|
|
client, err := lego.NewClient(config)
|
|
require.NoError(t, err)
|
|
|
|
client.Challenge.Exclude([]challenge.Type{challenge.DNS01, challenge.HTTP01})
|
|
err = client.Challenge.SetTLSALPN01Address(":5001")
|
|
require.NoError(t, err)
|
|
|
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
require.NoError(t, err)
|
|
user.registration = reg
|
|
|
|
csrRaw, err := ioutil.ReadFile("./fixtures/csr.raw")
|
|
require.NoError(t, err)
|
|
|
|
csr, err := x509.ParseCertificateRequest(csrRaw)
|
|
require.NoError(t, err)
|
|
|
|
resource, err := client.Certificate.ObtainForCSR(*csr, true)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, resource)
|
|
assert.Equal(t, "acme.wtf", resource.Domain)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
|
|
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
|
|
assert.NotEmpty(t, resource.Certificate)
|
|
assert.NotEmpty(t, resource.IssuerCertificate)
|
|
assert.NotEmpty(t, resource.CSR)
|
|
}
|
|
|
|
type fakeUser struct {
|
|
email string
|
|
privateKey crypto.PrivateKey
|
|
registration *registration.Resource
|
|
}
|
|
|
|
func (f *fakeUser) GetEmail() string { return f.email }
|
|
func (f *fakeUser) GetRegistration() *registration.Resource { return f.registration }
|
|
func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey }
|