Skip to content

Commit 83e4680

Browse files
committed
acme: DeactivateReg fix panic
Currently discover is not called which results in a panic if just a key is added to an ACME client and then deactivation is attempted. This patch adds a discover call as well as missing unit tests for the API.
1 parent 403b017 commit 83e4680

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

acme/rfc8555.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import (
2424
//
2525
// It only works with CAs implementing RFC 8555.
2626
func (c *Client) DeactivateReg(ctx context.Context) error {
27+
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
28+
return err
29+
}
2730
url := string(c.accountKID(ctx))
2831
if url == "" {
2932
return ErrNoAccount

acme/rfc8555_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,107 @@ func TestRFC_AccountKeyRollover(t *testing.T) {
644644
}
645645
}
646646

647+
func TestRFC_DeactivateReg(t *testing.T) {
648+
const email = "mailto:[email protected]"
649+
curStatus := StatusValid
650+
651+
type account struct {
652+
Status string `json:"status"`
653+
Contact []string `json:"contact"`
654+
AcceptTOS bool `json:"termsOfServiceAgreed"`
655+
Orders string `json:"orders"`
656+
}
657+
658+
s := newACMEServer()
659+
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
660+
w.Header().Set("Location", s.url("/accounts/1"))
661+
w.WriteHeader(http.StatusOK) // 200 means existing account
662+
json.NewEncoder(w).Encode(account{
663+
Status: curStatus,
664+
Contact: []string{email},
665+
AcceptTOS: true,
666+
Orders: s.url("/accounts/1/orders"),
667+
})
668+
669+
b, _ := ioutil.ReadAll(r.Body) // check err later in decodeJWSxxx
670+
head, err := decodeJWSHead(bytes.NewReader(b))
671+
if err != nil {
672+
t.Errorf("decodeJWSHead: %v", err)
673+
return
674+
}
675+
if len(head.JWK) == 0 {
676+
t.Error("head.JWK is empty")
677+
}
678+
679+
var req struct {
680+
Status string `json:"status"`
681+
Contact []string `json:"contact"`
682+
AcceptTOS bool `json:"termsOfServiceAgreed"`
683+
OnlyExisting bool `json:"onlyReturnExisting"`
684+
}
685+
decodeJWSRequest(t, &req, bytes.NewReader(b))
686+
if !req.OnlyExisting {
687+
t.Errorf("req.OnlyReturnExisting = %t; want = %t", req.OnlyExisting, true)
688+
}
689+
})
690+
s.handle("/accounts/1", func(w http.ResponseWriter, r *http.Request) {
691+
if curStatus == StatusValid {
692+
curStatus = StatusDeactivated
693+
w.WriteHeader(http.StatusOK)
694+
} else {
695+
s.error(w, &wireError{
696+
Status: http.StatusUnauthorized,
697+
Type: "urn:ietf:params:acme:error:unauthorized",
698+
})
699+
}
700+
var req account
701+
b, _ := ioutil.ReadAll(r.Body) // check err later in decodeJWSxxx
702+
head, err := decodeJWSHead(bytes.NewReader(b))
703+
if err != nil {
704+
t.Errorf("decodeJWSHead: %v", err)
705+
return
706+
}
707+
if len(head.JWK) != 0 {
708+
t.Error("head.JWK is not empty")
709+
}
710+
if !strings.HasSuffix(head.KID, "/accounts/1") {
711+
t.Errorf("head.KID = %q; want suffix /accounts/1", head.KID)
712+
}
713+
714+
decodeJWSRequest(t, &req, bytes.NewReader(b))
715+
if req.Status != StatusDeactivated {
716+
t.Errorf("req.Status = %q; want = %q", req.Status, StatusDeactivated)
717+
}
718+
})
719+
s.start()
720+
defer s.close()
721+
722+
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
723+
if err := cl.DeactivateReg(context.Background()); err != nil {
724+
t.Errorf("DeactivateReg: %v, wanted no error", err)
725+
}
726+
if err := cl.DeactivateReg(context.Background()); err == nil {
727+
t.Errorf("DeactivateReg: %v, wanted error for unauthorized", err)
728+
}
729+
}
730+
731+
func TestRF_DeactivateRegNoAccount(t *testing.T) {
732+
s := newACMEServer()
733+
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
734+
s.error(w, &wireError{
735+
Status: http.StatusBadRequest,
736+
Type: "urn:ietf:params:acme:error:accountDoesNotExist",
737+
})
738+
})
739+
s.start()
740+
defer s.close()
741+
742+
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
743+
if err := cl.DeactivateReg(context.Background()); !errors.Is(err, ErrNoAccount) {
744+
t.Errorf("DeactivateReg: %v, wanted ErrNoAccount", err)
745+
}
746+
}
747+
647748
func TestRFC_AuthorizeOrder(t *testing.T) {
648749
s := newACMEServer()
649750
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)