From 5e5a76c3b53e0edc1c654f8b334e651e9b9e3b21 Mon Sep 17 00:00:00 2001 From: David Cowden Date: Wed, 13 May 2020 11:10:14 -0700 Subject: [PATCH] acme/api: Set Link and Location headers for all 200 On the challenge resource, set "Link" and "Location" headers for all successful requests to the challenge resource. --- acme/api/handler.go | 22 ++++++++-------------- acme/api/handler_test.go | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/acme/api/handler.go b/acme/api/handler.go index 13ce6f99..b204e256 100644 --- a/acme/api/handler.go +++ b/acme/api/handler.go @@ -216,23 +216,17 @@ func (h *Handler) GetChallenge(w http.ResponseWriter, r *http.Request) { return } - switch ch.Status { - case acme.StatusPending: - panic("validation attempt did not move challenge to the processing state") - // When a transient error occurs, the challenge will not be progressed to the `invalid` state. - // Add a Retry-After header to indicate that the client should check again in the future. - case acme.StatusProcessing: + getLink := h.Auth.GetLink + w.Header().Add("Link", link(getLink(acme.AuthzLink, acme.URLSafeProvisionerName(prov), true, ch.GetAuthzID()), "up")) + w.Header().Set("Location", getLink(acme.ChallengeLink, acme.URLSafeProvisionerName(prov), true, ch.GetID())) + + if ch.Status == acme.StatusProcessing { w.Header().Add("Retry-After", ch.RetryAfter) + // 200s are cachable. Don't cache this because it will likely change. w.Header().Add("Cache-Control", "no-cache") - api.JSON(w, ch) - case acme.StatusValid, acme.StatusInvalid: - getLink := h.Auth.GetLink - w.Header().Add("Link", link(getLink(acme.AuthzLink, acme.URLSafeProvisionerName(prov), true, ch.GetAuthzID()), "up")) - w.Header().Set("Location", getLink(acme.ChallengeLink, acme.URLSafeProvisionerName(prov), true, ch.GetID())) - api.JSON(w, ch) - default: - panic("unexpected challenge state" + ch.Status) } + + api.JSON(w, ch) } // GetCertificate ACME api for retrieving a Certificate. diff --git a/acme/api/handler_test.go b/acme/api/handler_test.go index 9b8d0491..f4ec41b5 100644 --- a/acme/api/handler_test.go +++ b/acme/api/handler_test.go @@ -742,6 +742,7 @@ func TestHandlerGetChallenge(t *testing.T) { chJSON, err := json.Marshal(ch) assert.FatalError(t, err) ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{value: chJSON}) + count := 0 return test{ auth: &mockAcmeAuthority{ validateChallenge: func(p provisioner.Interface, accID, id string, jwk *jose.JSONWebKey) (*acme.Challenge, error) { @@ -751,7 +752,27 @@ func TestHandlerGetChallenge(t *testing.T) { assert.Equals(t, jwk.KeyID, key.KeyID) return &ch, nil }, + getLink: func(typ acme.Link, provID string, abs bool, in ...string) string { + var ret string + switch count { + case 0: + assert.Equals(t, typ, acme.AuthzLink) + assert.Equals(t, provID, acme.URLSafeProvisionerName(prov)) + assert.True(t, abs) + assert.Equals(t, in, []string{ch.AuthzID}) + ret = fmt.Sprintf("https://ca.smallstep.com/acme/authz/%s", ch.AuthzID) + case 1: + assert.Equals(t, typ, acme.ChallengeLink) + assert.Equals(t, provID, acme.URLSafeProvisionerName(prov)) + assert.True(t, abs) + assert.Equals(t, in, []string{ch.ID}) + ret = url + } + count++ + return ret + }, }, + ctx: ctx, statusCode: 200, ch: ch,