test: Add HTTP client for chall-test-srv (#8095)
This commit is contained in:
parent
76de5bf561
commit
c87c917348
|
|
@ -0,0 +1,505 @@
|
||||||
|
package challtestsrvclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client is an HTTP client for https://github.com/letsencrypt/challtestsrv's
|
||||||
|
// management interface (test/chall-test-srv).
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a new Client using the provided baseURL, or defaults to
|
||||||
|
// http://10.77.77.77:8055 if none is provided.
|
||||||
|
func NewClient(baseURL string) *Client {
|
||||||
|
if baseURL == "" {
|
||||||
|
baseURL = "http://10.77.77.77:8055"
|
||||||
|
}
|
||||||
|
return &Client{baseURL: baseURL}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
setIPv4 = "set-default-ipv4"
|
||||||
|
setIPv6 = "set-default-ipv6"
|
||||||
|
delHistory = "clear-request-history"
|
||||||
|
getHTTPHistory = "http-request-history"
|
||||||
|
getDNSHistory = "dns-request-history"
|
||||||
|
getALPNHistory = "tlsalpn01-request-history"
|
||||||
|
addA = "add-a"
|
||||||
|
delA = "clear-a"
|
||||||
|
addAAAA = "add-aaaa"
|
||||||
|
delAAAA = "clear-aaaa"
|
||||||
|
addCAA = "add-caa"
|
||||||
|
delCAA = "clear-caa"
|
||||||
|
addRedirect = "add-redirect"
|
||||||
|
delRedirect = "del-redirect"
|
||||||
|
addHTTP = "add-http01"
|
||||||
|
delHTTP = "del-http01"
|
||||||
|
addTXT = "set-txt"
|
||||||
|
delTXT = "clear-txt"
|
||||||
|
addALPN = "add-tlsalpn01"
|
||||||
|
delALPN = "del-tlsalpn01"
|
||||||
|
addServfail = "set-servfail"
|
||||||
|
delServfail = "clear-servfail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) postURL(path string, body interface{}) ([]byte, error) {
|
||||||
|
endpoint, err := url.JoinPath(c.baseURL, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("joining URL %q with path %q: %w", c.baseURL, path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("marshalling payload for %s: %w", endpoint, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Post(endpoint, "application/json", bytes.NewBuffer(payload))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("sending POST to %s: %w", endpoint, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("unexpected status code %d from %s", resp.StatusCode, endpoint)
|
||||||
|
}
|
||||||
|
respBytes, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading response from %s: %w", endpoint, err)
|
||||||
|
}
|
||||||
|
return respBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultIPv4 sets the challenge server's default IPv4 address used to
|
||||||
|
// respond to A queries when there are no specific mock A addresses for the
|
||||||
|
// hostname being queried. Provide an empty string as the default address to
|
||||||
|
// disable answering A queries except for hosts that have mock A addresses
|
||||||
|
// added. Any failure returns an error that includes both the relevant operation
|
||||||
|
// and the payload.
|
||||||
|
func (c *Client) SetDefaultIPv4(addr string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"ip": addr}
|
||||||
|
resp, err := c.postURL(setIPv4, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while setting default IPv4 to %q (payload: %v): %w",
|
||||||
|
addr, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultIPv6 sets the challenge server's default IPv6 address used to
|
||||||
|
// respond to AAAA queries when there are no specific mock AAAA addresses for
|
||||||
|
// the hostname being queried. Provide an empty string as the default address to
|
||||||
|
// disable answering AAAA queries except for hosts that have mock AAAA addresses
|
||||||
|
// added. Any failure returns an error that includes both the relevant operation
|
||||||
|
// and the payload.
|
||||||
|
func (c *Client) SetDefaultIPv6(addr string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"ip": addr}
|
||||||
|
resp, err := c.postURL(setIPv6, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while setting default IPv6 to %q (payload: %v): %w",
|
||||||
|
addr, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddARecord adds a mock A response to the challenge server's DNS interface for
|
||||||
|
// the given host and IPv4 addresses. Any failure returns an error that includes
|
||||||
|
// both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddARecord(host string, addresses []string) ([]byte, error) {
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"host": host,
|
||||||
|
"addresses": addresses,
|
||||||
|
}
|
||||||
|
resp, err := c.postURL(addA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding A record for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveARecord removes a mock A response from the challenge server's DNS
|
||||||
|
// interface for the given host. Any failure returns an error that includes both
|
||||||
|
// the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveARecord(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing A record for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAAAARecord adds a mock AAAA response to the challenge server's DNS
|
||||||
|
// interface for the given host and IPv6 addresses. Any failure returns an error
|
||||||
|
// that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddAAAARecord(host string, addresses []string) ([]byte, error) {
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"host": host,
|
||||||
|
"addresses": addresses,
|
||||||
|
}
|
||||||
|
resp, err := c.postURL(addAAAA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding AAAA record for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAAAARecord removes mock AAAA response from the challenge server's DNS
|
||||||
|
// interface for the given host. Any failure returns an error that includes both
|
||||||
|
// the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveAAAARecord(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delAAAA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing AAAA record for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCAAIssue adds a mock CAA response to the challenge server's DNS interface.
|
||||||
|
// The mock CAA response will contain one policy with an "issue" tag specifying
|
||||||
|
// the provided value. Any failure returns an error that includes both the
|
||||||
|
// relevant operation and the payload.
|
||||||
|
func (c *Client) AddCAAIssue(host, value string) ([]byte, error) {
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"host": host,
|
||||||
|
"policies": []map[string]string{
|
||||||
|
{"tag": "issue", "value": value},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := c.postURL(addCAA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding CAA issue for host %q, val %q (payload: %v): %w",
|
||||||
|
host, value, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveCAAIssue removes a mock CAA response from the challenge server's DNS
|
||||||
|
// interface for the given host. Any failure returns an error that includes both
|
||||||
|
// the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveCAAIssue(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delCAA, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing CAA issue for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPRequest is a single HTTP request in the request history.
|
||||||
|
type HTTPRequest struct {
|
||||||
|
URL string `json:"URL"`
|
||||||
|
Host string `json:"Host"`
|
||||||
|
HTTPS bool `json:"HTTPS"`
|
||||||
|
ServerName string `json:"ServerName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPRequestHistory fetches the challenge server's HTTP request history for
|
||||||
|
// the given host.
|
||||||
|
func (c *Client) HTTPRequestHistory(host string) ([]HTTPRequest, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
raw, err := c.postURL(getHTTPHistory, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while fetching HTTP request history for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var data []HTTPRequest
|
||||||
|
err = json.Unmarshal(raw, &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshalling HTTP request history: %w", err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) clearRequestHistory(host, typ string) ([]byte, error) {
|
||||||
|
return c.postURL(delHistory, map[string]string{"host": host, "type": typ})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearHTTPRequestHistory clears the challenge server's HTTP request history
|
||||||
|
// for the given host. Any failure returns an error that includes both the
|
||||||
|
// relevant operation and the payload.
|
||||||
|
func (c *Client) ClearHTTPRequestHistory(host string) ([]byte, error) {
|
||||||
|
resp, err := c.clearRequestHistory(host, "http")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while clearing HTTP request history for host %q: %w", host, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHTTPRedirect adds a redirect to the challenge server's HTTP interfaces for
|
||||||
|
// HTTP requests to the given path directing the client to the targetURL.
|
||||||
|
// Redirects are not served for HTTPS requests. Any failure returns an error
|
||||||
|
// that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddHTTPRedirect(path, targetURL string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"path": path, "targetURL": targetURL}
|
||||||
|
resp, err := c.postURL(addRedirect, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding HTTP redirect for path %q -> %q (payload: %v): %w",
|
||||||
|
path, targetURL, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveHTTPRedirect removes a redirect from the challenge server's HTTP
|
||||||
|
// interfaces for the given path. Any failure returns an error that includes
|
||||||
|
// both the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveHTTPRedirect(path string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"path": path}
|
||||||
|
resp, err := c.postURL(delRedirect, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing HTTP redirect for path %q (payload: %v): %w",
|
||||||
|
path, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHTTP01Response adds an ACME HTTP-01 challenge response for the provided
|
||||||
|
// token under the /.well-known/acme-challenge/ path of the challenge test
|
||||||
|
// server's HTTP interfaces. The given keyauth will be returned as the HTTP
|
||||||
|
// response body for requests to the challenge token. Any failure returns an
|
||||||
|
// error that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddHTTP01Response(token, keyauth string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"token": token, "content": keyauth}
|
||||||
|
resp, err := c.postURL(addHTTP, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding HTTP-01 challenge response for token %q (payload: %v): %w",
|
||||||
|
token, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveHTTP01Response removes an ACME HTTP-01 challenge response for the
|
||||||
|
// provided token from the challenge test server. Any failure returns an error
|
||||||
|
// that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveHTTP01Response(token string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"token": token}
|
||||||
|
resp, err := c.postURL(delHTTP, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing HTTP-01 challenge response for token %q (payload: %v): %w",
|
||||||
|
token, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServfailResponse configures the challenge test server to return SERVFAIL
|
||||||
|
// for all queries made for the provided host. This will override any other
|
||||||
|
// mocks for the host until removed with remove_servfail_response. Any failure
|
||||||
|
// returns an error that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddServfailResponse(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(addServfail, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding SERVFAIL response for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveServfailResponse undoes the work of AddServfailResponse, removing the
|
||||||
|
// SERVFAIL configuration for the given host. Any failure returns an error that
|
||||||
|
// includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveServfailResponse(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delServfail, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing SERVFAIL response for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDNS01Response adds an ACME DNS-01 challenge response for the provided host
|
||||||
|
// to the challenge test server's DNS interfaces. The provided value will be
|
||||||
|
// served for TXT queries for _acme-challenge.<host>. Any failure returns an
|
||||||
|
// error that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddDNS01Response(host, value string) ([]byte, error) {
|
||||||
|
if !strings.HasSuffix(host, ".") {
|
||||||
|
host += "."
|
||||||
|
}
|
||||||
|
payload := map[string]string{"host": host, "value": value}
|
||||||
|
resp, err := c.postURL(addTXT, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding DNS-01 response for host %q, val %q (payload: %v): %w",
|
||||||
|
host, value, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveDNS01Response removes an ACME DNS-01 challenge response for the
|
||||||
|
// provided host from the challenge test server's DNS interfaces. Any failure
|
||||||
|
// returns an error that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) RemoveDNS01Response(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delTXT, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing DNS-01 response for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSRequest is a single DNS request in the request history.
|
||||||
|
type DNSRequest struct {
|
||||||
|
Question struct {
|
||||||
|
Name string `json:"Name"`
|
||||||
|
Qtype int `json:"Qtype"`
|
||||||
|
Qclass int `json:"Qclass"`
|
||||||
|
} `json:"Question"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSRequestHistory returns the history of DNS requests made to the challenge
|
||||||
|
// test server's DNS interfaces for the given host. Any failure returns an error
|
||||||
|
// that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) DNSRequestHistory(host string) ([]DNSRequest, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
raw, err := c.postURL(getDNSHistory, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while fetching DNS request history for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var data []DNSRequest
|
||||||
|
err = json.Unmarshal(raw, &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshalling DNS request history: %w", err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearDNSRequestHistory clears the history of DNS requests made to the
|
||||||
|
// challenge test server's DNS interfaces for the given host. Any failure
|
||||||
|
// returns an error that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) ClearDNSRequestHistory(host string) ([]byte, error) {
|
||||||
|
resp, err := c.clearRequestHistory(host, "dns")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while clearing DNS request history for host %q: %w", host, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSALPN01Request is a single TLS-ALPN-01 request in the request history.
|
||||||
|
type TLSALPN01Request struct {
|
||||||
|
ServerName string `json:"ServerName"`
|
||||||
|
SupportedProtos []string `json:"SupportedProtos"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTLSALPN01Response adds an ACME TLS-ALPN-01 challenge response certificate
|
||||||
|
// to the challenge test server's TLS-ALPN-01 interface for the given host. The
|
||||||
|
// provided key authorization value will be embedded in the response certificate
|
||||||
|
// served to clients that initiate a TLS-ALPN-01 challenge validation with the
|
||||||
|
// challenge test server for the provided host. Any failure returns an error
|
||||||
|
// that includes both the relevant operation and the payload.
|
||||||
|
func (c *Client) AddTLSALPN01Response(host, value string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host, "content": value}
|
||||||
|
resp, err := c.postURL(addALPN, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while adding TLS-ALPN-01 response for host %q, val %q (payload: %v): %w",
|
||||||
|
host, value, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTLSALPN01Response removes an ACME TLS-ALPN-01 challenge response
|
||||||
|
// certificate from the challenge test server's TLS-ALPN-01 interface for the
|
||||||
|
// given host. Any failure returns an error that includes both the relevant
|
||||||
|
// operation and the payload.
|
||||||
|
func (c *Client) RemoveTLSALPN01Response(host string) ([]byte, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
resp, err := c.postURL(delALPN, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while removing TLS-ALPN-01 response for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSALPN01RequestHistory returns the history of TLS-ALPN-01 requests made to
|
||||||
|
// the challenge test server's TLS-ALPN-01 interface for the given host. Any
|
||||||
|
// failure returns an error that includes both the relevant operation and the
|
||||||
|
// payload.
|
||||||
|
func (c *Client) TLSALPN01RequestHistory(host string) ([]TLSALPN01Request, error) {
|
||||||
|
payload := map[string]string{"host": host}
|
||||||
|
raw, err := c.postURL(getALPNHistory, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while fetching TLS-ALPN-01 request history for host %q (payload: %v): %w",
|
||||||
|
host, payload, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var data []TLSALPN01Request
|
||||||
|
err = json.Unmarshal(raw, &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshalling TLS-ALPN-01 request history: %w", err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearTLSALPN01RequestHistory clears the history of TLS-ALPN-01 requests made
|
||||||
|
// to the challenge test server's TLS-ALPN-01 interface for the given host. Any
|
||||||
|
// failure returns an error that includes both the relevant operation and the
|
||||||
|
// payload.
|
||||||
|
func (c *Client) ClearTLSALPN01RequestHistory(host string) ([]byte, error) {
|
||||||
|
resp, err := c.clearRequestHistory(host, "tlsalpn")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"while clearing TLS-ALPN-01 request history for host %q: %w", host, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
@ -37,9 +37,12 @@ func TestFermat(t *testing.T) {
|
||||||
chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01]
|
chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01]
|
||||||
test.Assert(t, ok, "getting HTTP-01 challenge")
|
test.Assert(t, ok, "getting HTTP-01 challenge")
|
||||||
|
|
||||||
err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
|
_, err = testSrvClient.AddHTTP01Response(chal.Token, chal.KeyAuthorization)
|
||||||
defer delHTTP01Response(chal.Token)
|
test.AssertNotError(t, err, "")
|
||||||
test.AssertNotError(t, err, "adding HTTP-01 response")
|
defer func() {
|
||||||
|
_, err = testSrvClient.RemoveHTTP01Response(chal.Token)
|
||||||
|
test.AssertNotError(t, err, "")
|
||||||
|
}()
|
||||||
|
|
||||||
chal, err = c.Client.UpdateChallenge(c.Account, chal)
|
chal, err = c.Client.UpdateChallenge(c.Account, chal)
|
||||||
test.AssertNotError(t, err, "updating HTTP-01 challenge")
|
test.AssertNotError(t, err, "updating HTTP-01 challenge")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
@ -13,12 +12,15 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
challTestSrvClient "github.com/letsencrypt/boulder/test/chall-test-srv-client"
|
||||||
|
|
||||||
"github.com/eggsampler/acme/v3"
|
"github.com/eggsampler/acme/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testSrvClient = challTestSrvClient.NewClient("")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Go tests get run in the directory their source code lives in. For these
|
// Go tests get run in the directory their source code lives in. For these
|
||||||
// test cases, that would be "test/integration." However, it's easier to
|
// test cases, that would be "test/integration." However, it's easier to
|
||||||
|
|
@ -58,55 +60,6 @@ func makeClient(contacts ...string) (*client, error) {
|
||||||
return &client{account, c}, nil
|
return &client{account, c}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addHTTP01Response(token, keyAuthorization string) error {
|
|
||||||
resp, err := http.Post("http://boulder.service.consul:8055/add-http01", "",
|
|
||||||
bytes.NewBufferString(fmt.Sprintf(`{
|
|
||||||
"token": "%s",
|
|
||||||
"content": "%s"
|
|
||||||
}`, token, keyAuthorization)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("adding http-01 response: %s", err)
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("adding http-01 response: status %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func delHTTP01Response(token string) error {
|
|
||||||
resp, err := http.Post("http://boulder.service.consul:8055/del-http01", "",
|
|
||||||
bytes.NewBufferString(fmt.Sprintf(`{
|
|
||||||
"token": "%s"
|
|
||||||
}`, token)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("deleting http-01 response: %s", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("deleting http-01 response: status %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addCAAIssueRecord(host string, issue string) error {
|
|
||||||
resp, err := http.Post("http://boulder.service.consul:8055/add-caa", "",
|
|
||||||
bytes.NewBufferString(fmt.Sprintf(`{
|
|
||||||
"host": "%s",
|
|
||||||
"policies": [{"tag": "issue", "value": "%s"}]
|
|
||||||
}`, host, issue)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("adding CAA record: %s", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("adding CAA record: status %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
|
func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
|
||||||
var err error
|
var err error
|
||||||
if c == nil {
|
if c == nil {
|
||||||
|
|
@ -141,16 +94,22 @@ func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Ident
|
||||||
return nil, nil, fmt.Errorf("no HTTP challenge at %s", authUrl)
|
return nil, nil, fmt.Errorf("no HTTP challenge at %s", authUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
|
_, err = testSrvClient.AddHTTP01Response(chal.Token, chal.KeyAuthorization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("adding HTTP-01 response: %s", err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
chal, err = c.Client.UpdateChallenge(c.Account, chal)
|
chal, err = c.Client.UpdateChallenge(c.Account, chal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
delHTTP01Response(chal.Token)
|
_, err = testSrvClient.RemoveHTTP01Response(chal.Token)
|
||||||
return nil, nil, fmt.Errorf("updating challenge: %s", err)
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
_, err = testSrvClient.RemoveHTTP01Response(chal.Token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
delHTTP01Response(chal.Token)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
csr, err := makeCSR(csrKey, idents, cn)
|
csr, err := makeCSR(csrKey, idents, cn)
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,16 @@ func TestCAARechecking(t *testing.T) {
|
||||||
t.Fatalf("no HTTP challenge found in %#v", authz)
|
t.Fatalf("no HTTP challenge found in %#v", authz)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
|
_, err = testSrvClient.AddHTTP01Response(chal.Token, chal.KeyAuthorization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("setting HTTP-01 challenge token: %s", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer delHTTP01Response(chal.Token)
|
defer func() {
|
||||||
|
_, err = testSrvClient.RemoveHTTP01Response(chal.Token)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
chal, err = client.Client.UpdateChallenge(client.Account, chal)
|
chal, err = client.Client.UpdateChallenge(client.Account, chal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -67,9 +72,9 @@ func TestCAARechecking(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the CAA record to now forbid issuance.
|
// Change the CAA record to now forbid issuance.
|
||||||
err = addCAAIssueRecord(domain, ";")
|
_, err = testSrvClient.AddCAAIssue(domain, ";")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("updating CAA record: %s", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to finalize the order created above. Due to our db manipulation, this
|
// Try to finalize the order created above. Due to our db manipulation, this
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue