From 1f83de14df312a49980cf0b48d13101190615af6 Mon Sep 17 00:00:00 2001 From: Alex Vaghin Date: Sun, 14 Aug 2016 22:48:00 +0200 Subject: [PATCH] acme: improve http-01 challenge API This makes http-01 handling more consistent with tls-sni-* methods and, hopefully, future implementation such as dns-01 and oob-01. Change-Id: If1a4a47ee8528ef19960fee4e6860392c1813fe6 Reviewed-on: https://go-review.googlesource.com/27011 Reviewed-by: Brad Fitzpatrick --- acme/internal/acme/acme.go | 31 ++++++++++++++++--------------- acme/internal/acme/acme_test.go | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/acme/internal/acme/acme.go b/acme/internal/acme/acme.go index ac9c5e0..a5554ff 100644 --- a/acme/internal/acme/acme.go +++ b/acme/internal/acme/acme.go @@ -377,22 +377,23 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error return v.challenge(), nil } -// HTTP01Handler creates a new handler which responds to a http-01 challenge. +// HTTP01ChallengeResponse returns the response for an http-01 challenge. +// Servers should respond with the value to HTTP requests at the URL path +// provided by HTTP01ChallengePath to validate the challenge and prove control +// over a domain name. +// // The token argument is a Challenge.Token value. -func (c *Client) HTTP01Handler(token string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.HasSuffix(r.URL.Path, token) { - w.WriteHeader(http.StatusNotFound) - return - } - w.Header().Set("content-type", "text/plain") - auth, err := keyAuth(c.Key.Public(), token) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.Write([]byte(auth)) - }) +func (c *Client) HTTP01ChallengeResponse(token string) (string, error) { + return keyAuth(c.Key.Public(), token) +} + +// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge +// should be provided by the servers. +// The response value can be obtained with HTTP01ChallengeResponse. +// +// The token argument is a Challenge.Token value. +func (c *Client) HTTP01ChallengePath(token string) string { + return "/.well-known/acme-challenge/" + token } // TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response. diff --git a/acme/internal/acme/acme_test.go b/acme/internal/acme/acme_test.go index 37378c5..56a69ae 100644 --- a/acme/internal/acme/acme_test.go +++ b/acme/internal/acme/acme_test.go @@ -892,3 +892,23 @@ func TestTLSSNI02ChallengeCert(t *testing.T) { t.Errorf("%v doesn't have %q", cert.DNSNames, name) } } + +func TestHTTP01Challenge(t *testing.T) { + const ( + token = "xxx" + // thumbprint is precomputed for testKey in jws_test.go + value = token + "." + testKeyThumbprint + urlpath = "/.well-known/acme-challenge/" + token + ) + client := &Client{Key: testKey} + val, err := client.HTTP01ChallengeResponse(token) + if err != nil { + t.Fatal(err) + } + if val != value { + t.Errorf("val = %q; want %q", val, value) + } + if path := client.HTTP01ChallengePath(token); path != urlpath { + t.Errorf("path = %q; want %q", path, urlpath) + } +}