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 <bradfitz@golang.org>
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 @@
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 @@
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)
+ }
+}