From f944096df80415fafc888544caecaab86a991785 Mon Sep 17 00:00:00 2001 From: Alex Vaghin Date: Wed, 7 Sep 2016 16:50:43 +0200 Subject: [PATCH] acme: implement authorization revocation As with other methods of the Client, this is an implementation for the v2 version of the spec. Change-Id: I7fa7e0b700212992125de32524801048b56ac5d0 Reviewed-on: https://go-review.googlesource.com/28593 Reviewed-by: Brad Fitzpatrick --- acme/acme.go | 28 ++++++++++++++++++++++++++++ acme/acme_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/acme/acme.go b/acme/acme.go index 4e4f9e3..45b3f78 100644 --- a/acme/acme.go +++ b/acme/acme.go @@ -380,6 +380,34 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati return v.authorization(url), nil } +// RevokeAuthorization relinquishes an existing authorization identified +// by the given URL. +// The url argument is an Authorization.URI value. +// +// If successful, the caller will be required to obtain a new authorization +// using the Authorize method before being able to request a new certificate +// for the domain associated with the authorization. +// +// It does not revoke existing certificates. +func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { + req := struct { + Resource string `json:"resource"` + Delete bool `json:"delete"` + }{ + Resource: "authz", + Delete: true, + } + res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req) + if err != nil { + return err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return responseError(res) + } + return nil +} + // WaitAuthorization polls an authorization at the given URL // until it is in one of the final states, StatusValid or StatusInvalid, // or the context is done. diff --git a/acme/acme_test.go b/acme/acme_test.go index c85a689..10e72c4 100644 --- a/acme/acme_test.go +++ b/acme/acme_test.go @@ -552,6 +552,40 @@ func TestWaitAuthorizationCancel(t *testing.T) { } } +func TestRevokeAuthorization(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == "HEAD" { + w.Header().Set("replay-nonce", "nonce") + return + } + switch r.URL.Path { + case "/1": + var req struct { + Resource string + Delete bool + } + decodeJWSRequest(t, &req, r) + if req.Resource != "authz" { + t.Errorf("req.Resource = %q; want authz", req.Resource) + } + if !req.Delete { + t.Errorf("req.Delete is false") + } + case "/2": + w.WriteHeader(http.StatusInternalServerError) + } + })) + defer ts.Close() + client := &Client{Key: testKey} + ctx := context.Background() + if err := client.RevokeAuthorization(ctx, ts.URL+"/1"); err != nil { + t.Errorf("err = %v", err) + } + if client.RevokeAuthorization(ctx, ts.URL+"/2") == nil { + t.Error("nil error") + } +} + func TestPollChallenge(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" {