From f71e27e787fff9feb9b62b8aec04c5cacaae7bca Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 10 Mar 2021 23:05:46 -0800 Subject: [PATCH] [acme db interface] unit test progress --- acme/api/account_test.go | 4 ++-- acme/api/handler.go | 12 ++++++++---- acme/api/handler_test.go | 37 ++++++++++++++----------------------- acme/api/middleware.go | 2 +- acme/api/middleware_test.go | 30 +++++++++++++++--------------- acme/certificate.go | 13 ------------- acme/errors.go | 10 +++++++--- 7 files changed, 47 insertions(+), 61 deletions(-) diff --git a/acme/api/account_test.go b/acme/api/account_test.go index d94819c7..831a218a 100644 --- a/acme/api/account_test.go +++ b/acme/api/account_test.go @@ -40,7 +40,7 @@ func newProv() provisioner.Interface { return p } -func TestNewAccountRequestValidate(t *testing.T) { +func TestNewAccountRequest_Validate(t *testing.T) { type test struct { nar *NewAccountRequest err *acme.Error @@ -96,7 +96,7 @@ func TestNewAccountRequestValidate(t *testing.T) { } } -func TestUpdateAccountRequestValidate(t *testing.T) { +func TestUpdateAccountRequest_Validate(t *testing.T) { type test struct { uar *UpdateAccountRequest err *acme.Error diff --git a/acme/api/handler.go b/acme/api/handler.go index a6d35bb3..3fe72d54 100644 --- a/acme/api/handler.go +++ b/acme/api/handler.go @@ -2,7 +2,9 @@ package api import ( "crypto/tls" + "crypto/x509" "encoding/json" + "encoding/pem" "fmt" "net" "net/http" @@ -259,10 +261,12 @@ func (h *Handler) GetCertificate(w http.ResponseWriter, r *http.Request) { return } - certBytes, err := cert.ToACME() - if err != nil { - api.WriteError(w, acme.WrapErrorISE(err, "error converting cert to ACME representation")) - return + var certBytes []byte + for _, c := range append([]*x509.Certificate{cert.Leaf}, cert.Intermediates...) { + certBytes = append(certBytes, pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: c.Raw, + })...) } api.LogCertificate(w, cert.Leaf) diff --git a/acme/api/handler_test.go b/acme/api/handler_test.go index 23db72a5..8621ca18 100644 --- a/acme/api/handler_test.go +++ b/acme/api/handler_test.go @@ -3,6 +3,7 @@ package api import ( "bytes" "context" + "crypto/x509" "encoding/json" "encoding/pem" "fmt" @@ -47,7 +48,7 @@ func TestHandler_GetNonce(t *testing.T) { } func TestHandler_GetDirectory(t *testing.T) { - linker := NewLinker("acme", "ca.smallstep.com") + linker := NewLinker("ca.smallstep.com", "acme") prov := newProv() provName := url.PathEscape(prov.GetName()) @@ -306,7 +307,7 @@ func TestHandler_GetCertificate(t *testing.T) { err: acme.NewError(acme.ErrorAccountDoesNotExistType, "account does not exist"), } }, - "fail/getCertificate-error": func(t *testing.T) test { + "fail/db.GetCertificate-error": func(t *testing.T) test { acc := &acme.Account{ID: "accID"} ctx := context.WithValue(context.Background(), accContextKey, acc) ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) @@ -319,7 +320,7 @@ func TestHandler_GetCertificate(t *testing.T) { err: acme.NewErrorISE("force"), } }, - "fail/decode-leaf-for-loggger": func(t *testing.T) test { + "fail/account-id-mismatch": func(t *testing.T) test { acc := &acme.Account{ID: "accID"} ctx := context.WithValue(context.Background(), accContextKey, acc) ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) @@ -327,28 +328,12 @@ func TestHandler_GetCertificate(t *testing.T) { db: &acme.MockDB{ MockGetCertificate: func(ctx context.Context, id string) (*acme.Certificate, error) { assert.Equals(t, id, certID) - return &acme.Certificate{}, nil + return &acme.Certificate{AccountID: "foo"}, nil }, }, ctx: ctx, - statusCode: 500, - err: acme.NewErrorISE("failed to decode any certificates from generated certBytes"), - } - }, - "fail/parse-x509-leaf-for-logger": func(t *testing.T) test { - acc := &acme.Account{ID: "accID"} - ctx := context.WithValue(context.Background(), accContextKey, acc) - ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) - return test{ - db: &acme.MockDB{ - MockGetCertificate: func(ctx context.Context, id string) (*acme.Certificate, error) { - assert.Equals(t, id, certID) - return &acme.Certificate{}, nil - }, - }, - ctx: ctx, - statusCode: 500, - err: acme.NewErrorISE("failed to parse generated leaf certificate"), + statusCode: 401, + err: acme.NewError(acme.ErrorUnauthorizedType, "account id mismatch"), } }, "ok": func(t *testing.T) test { @@ -359,7 +344,13 @@ func TestHandler_GetCertificate(t *testing.T) { db: &acme.MockDB{ MockGetCertificate: func(ctx context.Context, id string) (*acme.Certificate, error) { assert.Equals(t, id, certID) - return &acme.Certificate{}, nil + return &acme.Certificate{ + AccountID: "accID", + OrderID: "ordID", + Leaf: leaf, + Intermediates: []*x509.Certificate{inter, root}, + ID: id, + }, nil }, }, ctx: ctx, diff --git a/acme/api/middleware.go b/acme/api/middleware.go index 7a3529cd..f2a35c3a 100644 --- a/acme/api/middleware.go +++ b/acme/api/middleware.go @@ -411,7 +411,7 @@ const ( func accountFromContext(ctx context.Context) (*acme.Account, error) { val, ok := ctx.Value(accContextKey).(*acme.Account) if !ok || val == nil { - return nil, acme.NewErrorISE("account not in context") + return nil, acme.NewError(acme.ErrorAccountDoesNotExistType, "account not in context") } return val, nil } diff --git a/acme/api/middleware_test.go b/acme/api/middleware_test.go index c6c855a8..4f2c4bcb 100644 --- a/acme/api/middleware_test.go +++ b/acme/api/middleware_test.go @@ -81,7 +81,7 @@ func Test_baseURLFromRequest(t *testing.T) { } } -func TestHandlerBaseURLFromRequest(t *testing.T) { +func TestHandler_baseURLFromRequest(t *testing.T) { h := &Handler{} req := httptest.NewRequest("GET", "/foo", nil) req.Host = "test.ca.smallstep.com:8080" @@ -107,7 +107,7 @@ func TestHandlerBaseURLFromRequest(t *testing.T) { h.baseURLFromRequest(next)(w, req) } -func TestHandler_AddNonce(t *testing.T) { +func TestHandler_addNonce(t *testing.T) { url := "https://ca.smallstep.com/acme/new-nonce" type test struct { db acme.DB @@ -226,7 +226,7 @@ func TestHandler_addDirLink(t *testing.T) { } } -func TestHandler_VerifyContentType(t *testing.T) { +func TestHandler_verifyContentType(t *testing.T) { prov := newProv() provName := prov.GetName() baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"} @@ -340,7 +340,7 @@ func TestHandler_VerifyContentType(t *testing.T) { } } -func TestHandlerIsPostAsGet(t *testing.T) { +func TestHandler_isPostAsGet(t *testing.T) { url := "https://ca.smallstep.com/acme/new-account" type test struct { ctx context.Context @@ -417,7 +417,7 @@ func (errReader) Close() error { return nil } -func TestHandlerParseJWS(t *testing.T) { +func TestHandler_parseJWS(t *testing.T) { url := "https://ca.smallstep.com/acme/new-account" type test struct { next nextHTTP @@ -498,7 +498,7 @@ func TestHandlerParseJWS(t *testing.T) { } } -func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { +func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) _pub := jwk.Public() @@ -558,7 +558,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { assert.FatalError(t, err) _pub := _jwk.Public() ctx := context.WithValue(context.Background(), jwsContextKey, parsedJWS) - ctx = context.WithValue(ctx, jwsContextKey, &_pub) + ctx = context.WithValue(ctx, jwkContextKey, &_pub) return test{ ctx: ctx, statusCode: 400, @@ -570,7 +570,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { clone := &_pub clone.Algorithm = jose.HS256 ctx := context.WithValue(context.Background(), jwsContextKey, parsedJWS) - ctx = context.WithValue(ctx, jwsContextKey, clone) + ctx = context.WithValue(ctx, jwkContextKey, clone) return test{ ctx: ctx, statusCode: 400, @@ -579,7 +579,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { }, "ok": func(t *testing.T) test { ctx := context.WithValue(context.Background(), jwsContextKey, parsedJWS) - ctx = context.WithValue(ctx, jwsContextKey, pub) + ctx = context.WithValue(ctx, jwkContextKey, pub) return test{ ctx: ctx, statusCode: 200, @@ -600,7 +600,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { clone := &_pub clone.Algorithm = "" ctx := context.WithValue(context.Background(), jwsContextKey, parsedJWS) - ctx = context.WithValue(ctx, jwsContextKey, pub) + ctx = context.WithValue(ctx, jwkContextKey, pub) return test{ ctx: ctx, statusCode: 200, @@ -624,7 +624,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { _parsed, err := jose.ParseJWS(_raw) assert.FatalError(t, err) ctx := context.WithValue(context.Background(), jwsContextKey, _parsed) - ctx = context.WithValue(ctx, jwsContextKey, pub) + ctx = context.WithValue(ctx, jwkContextKey, pub) return test{ ctx: ctx, statusCode: 200, @@ -648,7 +648,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { _parsed, err := jose.ParseJWS(_raw) assert.FatalError(t, err) ctx := context.WithValue(context.Background(), jwsContextKey, _parsed) - ctx = context.WithValue(ctx, jwsContextKey, pub) + ctx = context.WithValue(ctx, jwkContextKey, pub) return test{ ctx: ctx, statusCode: 200, @@ -697,7 +697,7 @@ func TestHandlerVerifyAndExtractJWSPayload(t *testing.T) { } } -func TestHandlerLookupJWK(t *testing.T) { +func TestHandler_lookupJWK(t *testing.T) { prov := newProv() provName := url.PathEscape(prov.GetName()) baseURL := &url.URL{Scheme: "https", Host: "test.ca.smallstep.com"} @@ -899,7 +899,7 @@ func TestHandlerLookupJWK(t *testing.T) { } } -func TestHandlerExtractJWK(t *testing.T) { +func TestHandler_extractJWK(t *testing.T) { prov := newProv() provName := url.PathEscape(prov.GetName()) jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) @@ -1095,7 +1095,7 @@ func TestHandlerExtractJWK(t *testing.T) { } } -func TestHandlerValidateJWS(t *testing.T) { +func TestHandler_validateJWS(t *testing.T) { url := "https://ca.smallstep.com/acme/account/1234" type test struct { db acme.DB diff --git a/acme/certificate.go b/acme/certificate.go index daf9556b..d46d1a08 100644 --- a/acme/certificate.go +++ b/acme/certificate.go @@ -2,7 +2,6 @@ package acme import ( "crypto/x509" - "encoding/pem" ) // Certificate options with which to create and store a cert object. @@ -13,15 +12,3 @@ type Certificate struct { Leaf *x509.Certificate Intermediates []*x509.Certificate } - -// ToACME encodes the entire X509 chain into a PEM list. -func (cert *Certificate) ToACME() ([]byte, error) { - var ret []byte - for _, c := range append([]*x509.Certificate{cert.Leaf}, cert.Intermediates...) { - ret = append(ret, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: c.Raw, - })...) - } - return ret, nil -} diff --git a/acme/errors.go b/acme/errors.go index 41305c87..54182ec2 100644 --- a/acme/errors.go +++ b/acme/errors.go @@ -271,6 +271,10 @@ type Error struct { // NewError creates a new Error type. func NewError(pt ProblemType, msg string, args ...interface{}) *Error { + return newError(pt, errors.Errorf(msg, args...)) +} + +func newError(pt ProblemType, err error) *Error { meta, ok := errorMap[pt] if !ok { meta = errorServerInternalMetadata @@ -278,7 +282,7 @@ func NewError(pt ProblemType, msg string, args ...interface{}) *Error { Type: meta.typ, Detail: meta.details, Status: meta.status, - Err: errors.Errorf("unrecognized problemType %v", pt), + Err: err, } } @@ -286,7 +290,7 @@ func NewError(pt ProblemType, msg string, args ...interface{}) *Error { Type: meta.typ, Detail: meta.details, Status: meta.status, - Err: errors.Errorf(msg, args...), + Err: err, } } @@ -308,7 +312,7 @@ func WrapError(typ ProblemType, err error, msg string, args ...interface{}) *Err } return e default: - return NewError(ErrorServerInternalType, msg, args...) + return newError(typ, errors.Wrapf(err, msg, args...)) } }