cert-manager/third_party/crypto/acme/integration_test.go

147 lines
3.7 KiB
Go

// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build integration_test
package acme_test
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"net"
"net/http"
"os"
"reflect"
"testing"
"golang.org/x/crypto/acme"
)
// This test works with Pebble and Let's Encrypt staging.
// For pebble use: ACME_DIRECTORY_URL=https://localhost:14000/dir go test -tags integration_test
// For Let's Encrypt you'll need a publicly accessible HTTP server like `ngrok http 8080` and then
// TEST_HOST=xxx.ngrok.io:8080 ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory TEST_ACCOUNT_GET=1 TEST_REVOKE=1 go test -tags integration_test
func TestIntegration(t *testing.T) {
dir := os.Getenv("ACME_DIRECTORY_URL")
testAccountGet := os.Getenv("TEST_ACCOUNT_GET") != ""
testRevoke := os.Getenv("TEST_REVOKE") != ""
testHost := os.Getenv("TEST_HOST")
if testHost == "" {
testHost = "localhost:5002"
}
testIdentifier, listenPort, _ := net.SplitHostPort(testHost)
if dir == "" {
t.Fatal("ACME_DIRECTORY_URL is required")
}
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
c := &acme.Client{
Key: key,
DirectoryURL: dir,
HTTPClient: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
},
}
a := &acme.Account{
Contact: []string{"mailto:user@example.com"},
TermsAgreed: true,
}
na, err := c.CreateAccount(context.Background(), a)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(a.Contact, na.Contact) {
t.Errorf("na.Contact = %q; want %q", na.Contact, a.Contact)
}
if na.URL == "" {
t.Fatal("empty na.URL")
}
// this endpoint is not supported by pebble, so put it behind a flag
if testAccountGet {
na, err = c.GetAccount(context.Background())
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(a.Contact, na.Contact) {
t.Errorf("na.Contact = %q; want %q", na.Contact, a.Contact)
}
}
order, err := c.CreateOrder(context.Background(), acme.NewOrder(testIdentifier))
if err != nil {
t.Fatal(err)
}
auth, err := c.GetAuthorization(context.Background(), order.Authorizations[0])
if err != nil {
t.Fatal(err)
}
var challenge *acme.Challenge
for _, ch := range auth.Challenges {
if ch.Type == "http-01" {
challenge = ch
break
}
}
if challenge == nil {
t.Fatal("missing http-01 challenge")
}
l, err := net.Listen("tcp", ":"+listenPort)
if err != nil {
t.Errorf("error listening for challenge: %s", err)
}
defer l.Close()
go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != c.HTTP01ChallengePath(challenge.Token) {
w.WriteHeader(404)
return
}
res, _ := c.HTTP01ChallengeResponse(challenge.Token)
w.Write([]byte(res))
}))
_, err = c.AcceptChallenge(context.Background(), challenge)
if err != nil {
t.Fatal(err)
}
_, err = c.WaitAuthorization(context.Background(), order.Authorizations[0])
if err != nil {
t.Fatal(err)
}
certKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
csr, _ := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{DNSNames: []string{testIdentifier}}, certKey)
der, err := c.FinalizeOrder(context.Background(), order.FinalizeURL, csr)
if err != nil {
t.Fatal(err)
}
cert, err := x509.ParseCertificate(der[0])
if err != nil {
t.Fatal(err)
}
if cert.DNSNames[0] != testIdentifier {
t.Errorf("unexpected DNSNames %v", cert.DNSNames)
}
if testRevoke {
if err := c.RevokeCert(context.Background(), certKey, der[0], acme.CRLReasonUnspecified); err != nil {
t.Fatal(err)
}
}
}